mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 01:47:00 +01:00
meta - transactions - docs yo!
This commit is contained in:
parent
943eea043c
commit
eeb9390de8
92
app/scripts/controllers/transactions/README.md
Normal file
92
app/scripts/controllers/transactions/README.md
Normal file
@ -0,0 +1,92 @@
|
||||
# Transaction Controller
|
||||
|
||||
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
|
||||
|
||||
## flow digram of processing a transaction
|
||||
|
||||
![transaction-flow](../../../../docs/transaction-flow.png)
|
||||
|
||||
## txMeta's && txParams
|
||||
|
||||
A txMeta is the "meta" object it has all the random bits of info we need about a transaction on it. txParams are sacred every thing on txParams gets signed so it must
|
||||
be a valid key and be hex prefixed except for the network number. Extra stuff must go on the txMeta!
|
||||
|
||||
Here is a txMeta too look at:
|
||||
|
||||
```js
|
||||
txMeta = {
|
||||
"id": 2828415030114568, // unique id for this txMeta used for look ups
|
||||
"time": 1524094064821, // time of creation
|
||||
"status": "confirmed",
|
||||
"metamaskNetworkId": "1524091532133", //the network id for the transaction
|
||||
"loadingDefaults": false, // used to tell the ui when we are done calculatyig gass defaults
|
||||
"txParams": { // the txParams object
|
||||
"from": "0x8acce2391c0d510a6c5e5d8f819a678f79b7e675",
|
||||
"to": "0x8acce2391c0d510a6c5e5d8f819a678f79b7e675",
|
||||
"value": "0x0",
|
||||
"gasPrice": "0x3b9aca00",
|
||||
"gas": "0x7b0c",
|
||||
"nonce": "0x0"
|
||||
},
|
||||
"history": [{ //debug
|
||||
"id": 2828415030114568,
|
||||
"time": 1524094064821,
|
||||
"status": "unapproved",
|
||||
"metamaskNetworkId": "1524091532133",
|
||||
"loadingDefaults": true,
|
||||
"txParams": {
|
||||
"from": "0x8acce2391c0d510a6c5e5d8f819a678f79b7e675",
|
||||
"to": "0x8acce2391c0d510a6c5e5d8f819a678f79b7e675",
|
||||
"value": "0x0"
|
||||
}
|
||||
},
|
||||
[
|
||||
{
|
||||
"op": "add",
|
||||
"path": "/txParams/gasPrice",
|
||||
"value": "0x3b9aca00"
|
||||
},
|
||||
...], // I've removed most of history for this
|
||||
"gasPriceSpecified": false, //weather or not the user/dapp has specified gasPrice
|
||||
"gasLimitSpecified": false, //weather or not the user/dapp has specified gas
|
||||
"estimatedGas": "5208",
|
||||
"origin": "MetaMask", //debug
|
||||
"nonceDetails": {
|
||||
"params": {
|
||||
"highestLocallyConfirmed": 0,
|
||||
"highestSuggested": 0,
|
||||
"nextNetworkNonce": 0
|
||||
},
|
||||
"local": {
|
||||
"name": "local",
|
||||
"nonce": 0,
|
||||
"details": {
|
||||
"startPoint": 0,
|
||||
"highest": 0
|
||||
}
|
||||
},
|
||||
"network": {
|
||||
"name": "network",
|
||||
"nonce": 0,
|
||||
"details": {
|
||||
"baseCount": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"rawTx": "0xf86980843b9aca00827b0c948acce2391c0d510a6c5e5d8f819a678f79b7e67580808602c5b5de66eea05c01a320b96ac730cb210ca56d2cb71fa360e1fc2c21fa5cf333687d18eb323fa02ed05987a6e5fd0f2459fcff80710b76b83b296454ad9a37594a0ccb4643ea90", // used for rebroadcast
|
||||
"hash": "0xa45ba834b97c15e6ff4ed09badd04ecd5ce884b455eb60192cdc73bcc583972a",
|
||||
"submittedTime": 1524094077902 // time of the attempt to submit the raw tx to the network, used in the ui to show the retry button
|
||||
}
|
||||
```
|
@ -25,14 +25,15 @@ const txUtils = require('./lib/util')
|
||||
|
||||
|
||||
@param {object} opts -
|
||||
- initState, initial transaction list default is an empty array<br>
|
||||
- networkStore, an observable store for network number<br>
|
||||
- blockTracker,<br>
|
||||
- provider,<br>
|
||||
- signTransaction, function the signs an ethereumjs-tx<br>
|
||||
- getGasPrice, optional gas price calculator<br>
|
||||
- txHistoryLimit, number *optional* for limiting how many transactions are in state <br>
|
||||
- preferencesStore,
|
||||
@property {object} opts.initState initial transaction list default is an empty array
|
||||
@property {Object} opts.networkStore an observable store for network number
|
||||
@property {Object} opts.blockTracker
|
||||
@property {Object} opts.provider
|
||||
@property {Object} opts.signTransaction function the signs an ethereumjs-tx
|
||||
@property {function} opts.getGasPrice optional gas price calculator
|
||||
@property {function} opts.signTransaction ethTx signer that returns a rawTx
|
||||
@property {number} opts.txHistoryLimit number *optional* for limiting how many transactions are in state
|
||||
@property {Object} opts.preferencesStore
|
||||
@class
|
||||
*/
|
||||
|
||||
@ -50,12 +51,12 @@ class TransactionController extends EventEmitter {
|
||||
this.query = new EthQuery(this.provider)
|
||||
this.txGasUtil = new TxGasUtil(this.provider)
|
||||
|
||||
this._mapMethods()
|
||||
this.txStateManager = new TransactionStateManager({
|
||||
initState: opts.initState,
|
||||
txHistoryLimit: opts.txHistoryLimit,
|
||||
getNetwork: this.getNetwork.bind(this),
|
||||
})
|
||||
this._mapMethods()
|
||||
this._onBootCleanUp()
|
||||
|
||||
this.store = this.txStateManager.store
|
||||
@ -92,7 +93,10 @@ class TransactionController extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds a tx to the txlist */
|
||||
/**
|
||||
Adds a tx to the txlist
|
||||
@emits ${txMeta.id}:unapproved
|
||||
*/
|
||||
addTx (txMeta) {
|
||||
this.txStateManager.addTx(txMeta)
|
||||
this.emit(`${txMeta.id}:unapproved`, txMeta)
|
||||
@ -172,6 +176,7 @@ add a new unapproved transaction to the pipeline
|
||||
async addTxGasDefaults (txMeta) {
|
||||
const txParams = txMeta.txParams
|
||||
// ensure value
|
||||
txParams.value = txParams.value ? ethUtil.addHexPrefix(value) : '0x0',
|
||||
txMeta.gasPriceSpecified = Boolean(txParams.gasPrice)
|
||||
let gasPrice = txParams.gasPrice
|
||||
if (!gasPrice) {
|
||||
@ -412,4 +417,4 @@ add a new unapproved transaction to the pipeline
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TransactionController
|
||||
module.exports = TransactionController
|
||||
|
@ -1,6 +1,6 @@
|
||||
const jsonDiffer = require('fast-json-patch')
|
||||
const clone = require('clone')
|
||||
|
||||
/** @module*/
|
||||
module.exports = {
|
||||
generateHistoryEntry,
|
||||
replayHistory,
|
||||
@ -8,7 +8,11 @@ module.exports = {
|
||||
migrateFromSnapshotsToDiffs,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
converts non-initial history entries into diffs
|
||||
@param longHistory {array}
|
||||
@returns {array}
|
||||
*/
|
||||
function migrateFromSnapshotsToDiffs (longHistory) {
|
||||
return (
|
||||
longHistory
|
||||
@ -20,6 +24,17 @@ function migrateFromSnapshotsToDiffs (longHistory) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
generates an array of history objects sense the previous state.
|
||||
The object has the keys opp(the operation preformed),
|
||||
path(the key and if a nested object then each key will be seperated with a `/`)
|
||||
value
|
||||
with the first entry having the note
|
||||
@param previousState {object} - the previous state of the object
|
||||
@param newState {object} - the update object
|
||||
@param note {string} - a optional note for the state change
|
||||
@reurns {array}
|
||||
*/
|
||||
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
|
||||
@ -27,11 +42,19 @@ function generateHistoryEntry (previousState, newState, note) {
|
||||
return entry
|
||||
}
|
||||
|
||||
/**
|
||||
Recovers previous txMeta state obj
|
||||
@return {object}
|
||||
*/
|
||||
function replayHistory (_shortHistory) {
|
||||
const shortHistory = clone(_shortHistory)
|
||||
return shortHistory.reduce((val, entry) => jsonDiffer.applyPatch(val, entry).newDocument)
|
||||
}
|
||||
|
||||
/**
|
||||
@param txMeta {object}
|
||||
@returns {object} a clone object of the txMeta with out history
|
||||
*/
|
||||
function snapshotFromTxMeta (txMeta) {
|
||||
// create txMeta snapshot for history
|
||||
const snapshot = clone(txMeta)
|
||||
|
@ -3,11 +3,15 @@ const {
|
||||
isValidAddress,
|
||||
} = require('ethereumjs-util')
|
||||
|
||||
/**
|
||||
@module
|
||||
*/
|
||||
module.exports = {
|
||||
normalizeTxParams,
|
||||
validateTxParams,
|
||||
validateFrom,
|
||||
validateRecipient,
|
||||
getFinalStates,
|
||||
}
|
||||
|
||||
|
||||
@ -16,22 +20,30 @@ const normalizers = {
|
||||
from: from => addHexPrefix(from).toLowerCase(),
|
||||
to: to => addHexPrefix(to).toLowerCase(),
|
||||
nonce: nonce => addHexPrefix(nonce),
|
||||
value: value => value ? addHexPrefix(value) : '0x0',
|
||||
value: value => addHexPrefix(value),
|
||||
data: data => addHexPrefix(data),
|
||||
gas: gas => addHexPrefix(gas),
|
||||
gasPrice: gasPrice => addHexPrefix(gasPrice),
|
||||
}
|
||||
|
||||
/**
|
||||
normalizes txParams
|
||||
@param txParams {object}
|
||||
@returns {object} normalized txParams
|
||||
*/
|
||||
function normalizeTxParams (txParams) {
|
||||
// apply only keys in the normalizers
|
||||
const normalizedTxParams = {}
|
||||
for (let key in normalizers) {
|
||||
for (const key in normalizers) {
|
||||
if (txParams[key]) normalizedTxParams[key] = normalizers[key](txParams[key])
|
||||
}
|
||||
return normalizedTxParams
|
||||
}
|
||||
|
||||
/**
|
||||
validates txParams
|
||||
@param txParams {object}
|
||||
*/
|
||||
function validateTxParams (txParams) {
|
||||
validateFrom(txParams)
|
||||
validateRecipient(txParams)
|
||||
@ -47,11 +59,19 @@ function validateTxParams (txParams) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
validates the from field in txParams
|
||||
@param txParams {object}
|
||||
*/
|
||||
function validateFrom (txParams) {
|
||||
if (!(typeof txParams.from === 'string')) throw new Error(`Invalid from address ${txParams.from} not a string`)
|
||||
if (!isValidAddress(txParams.from)) throw new Error('Invalid from address')
|
||||
}
|
||||
|
||||
/**
|
||||
validates the to field in txParams
|
||||
@param txParams {object}
|
||||
*/
|
||||
function validateRecipient (txParams) {
|
||||
if (txParams.to === '0x' || txParams.to === null) {
|
||||
if (txParams.data) {
|
||||
@ -64,3 +84,16 @@ function validateRecipient (txParams) {
|
||||
}
|
||||
return txParams
|
||||
}
|
||||
|
||||
/**
|
||||
@returns an {array} of states that can be considered final
|
||||
*/
|
||||
function getFinalStates () {
|
||||
return [
|
||||
'rejected', // the user has responded no!
|
||||
'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
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,15 @@
|
||||
const EthQuery = require('ethjs-query')
|
||||
const assert = require('assert')
|
||||
const Mutex = require('await-semaphore').Mutex
|
||||
|
||||
/**
|
||||
@param opts {object} -
|
||||
@property {Object} opts.provider a ethereum provider
|
||||
@property {function} opts.getPendingTransactions a function that returns an array of txMeta
|
||||
whos status is `submitted`
|
||||
@property {function} opts.getConfirmedTransactions a function that returns an array of txMeta
|
||||
whos status is `confirmed`
|
||||
@class
|
||||
*/
|
||||
class NonceTracker {
|
||||
|
||||
constructor ({ provider, getPendingTransactions, getConfirmedTransactions }) {
|
||||
@ -12,6 +20,9 @@ class NonceTracker {
|
||||
this.lockMap = {}
|
||||
}
|
||||
|
||||
/**
|
||||
@returns {object} with the key releaseLock (the gloabl mutex)
|
||||
*/
|
||||
async getGlobalLock () {
|
||||
const globalMutex = this._lookupMutex('global')
|
||||
// await global mutex free
|
||||
@ -19,8 +30,19 @@ class NonceTracker {
|
||||
return { releaseLock }
|
||||
}
|
||||
|
||||
// releaseLock must be called
|
||||
// releaseLock must be called after adding signed tx to pending transactions (or discarding)
|
||||
/**
|
||||
this will return an object with the `nextNonce` `nonceDetails` which is an
|
||||
object with:
|
||||
highestLocallyConfirmed (nonce),
|
||||
highestSuggested (either the network nonce or the highestLocallyConfirmed nonce),
|
||||
nextNetworkNonce (the nonce suggested by the network),
|
||||
and the releaseLock
|
||||
<br>note: releaseLock must be called after adding signed tx to pending transactions
|
||||
(or discarding)<br>
|
||||
|
||||
@param address {string} the hex string for the address whos nonce we are calculating
|
||||
@returns {object}
|
||||
*/
|
||||
async getNonceLock (address) {
|
||||
// await global mutex free
|
||||
await this._globalMutexFree()
|
||||
|
@ -8,10 +8,10 @@ const EthQuery = require('ethjs-query')
|
||||
As well as continues broadcast while in the pending state
|
||||
<br>
|
||||
@param config {object} - non optional configuration object consists of:
|
||||
<br>provider
|
||||
<br>nonceTracker: see nonce tracker
|
||||
<br>getPendingTransactions: a function for getting an array of transactions,
|
||||
<br>publishTransaction: a async function for publishing raw transactions,
|
||||
@property {Object} config.provider
|
||||
@property {Object} config.nonceTracker see nonce tracker
|
||||
@property {function} config.getPendingTransactions a function for getting an array of transactions,
|
||||
@property {function} config.publishTransaction a async function for publishing raw transactions,
|
||||
|
||||
|
||||
@class
|
||||
@ -220,4 +220,4 @@ class PendingTransactionTracker extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PendingTransactionTracker
|
||||
module.exports = PendingTransactionTracker
|
||||
|
@ -11,6 +11,7 @@ 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.
|
||||
@param provider {object}
|
||||
*/
|
||||
|
||||
module.exports = class TxGasUtil {
|
||||
|
@ -1,22 +1,33 @@
|
||||
const extend = require('xtend')
|
||||
const EventEmitter = require('events')
|
||||
const ObservableStore = require('obs-store')
|
||||
const createId = require('../../lib/random-id')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const txStateHistoryHelper = require('./lib/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 {
|
||||
const createId = require('../../lib/random-id')
|
||||
const { getFinalStates } = require('./lib/util')
|
||||
/**
|
||||
TransactionStateManager is responsible for the state of a transaction and
|
||||
storing the transaction
|
||||
it also has some convenience methods for finding subsets of transactions
|
||||
*
|
||||
*STATUS METHODS
|
||||
<br>statuses:
|
||||
<br> - `'unapproved'` the user has not responded
|
||||
<br> - `'rejected'` the user has responded no!
|
||||
<br> - `'approved'` the user has approved the tx
|
||||
<br> - `'signed'` the tx is signed
|
||||
<br> - `'submitted'` the tx is sent to a server
|
||||
<br> - `'confirmed'` the tx has been included in a block.
|
||||
<br> - `'failed'` the tx failed for some reason, included on tx data.
|
||||
<br> - `'dropped'` the tx nonce was already used
|
||||
@param opts {object} -
|
||||
@property {object} opts.initState with the key transaction {array}
|
||||
@property {number} opts.txHistoryLimit limit for how many finished
|
||||
transactions can hang around in state
|
||||
@property {function} opts.getNetwork return network number
|
||||
@class
|
||||
*/
|
||||
class TransactionStateManager extends EventEmitter {
|
||||
constructor ({ initState, txHistoryLimit, getNetwork }) {
|
||||
super()
|
||||
|
||||
@ -28,6 +39,10 @@ module.exports = class TransactionStateManager extends EventEmitter {
|
||||
this.getNetwork = getNetwork
|
||||
}
|
||||
|
||||
/**
|
||||
@param opts {object} - the object to use when overwriting defaults
|
||||
@returns {txMeta} the default txMeta object
|
||||
*/
|
||||
generateTxMeta (opts) {
|
||||
return extend({
|
||||
id: createId(),
|
||||
@ -38,17 +53,25 @@ module.exports = class TransactionStateManager extends EventEmitter {
|
||||
}, opts)
|
||||
}
|
||||
|
||||
/**
|
||||
@returns {array} of txMetas that have been filtered for only the current network
|
||||
*/
|
||||
getTxList () {
|
||||
const network = this.getNetwork()
|
||||
const fullTxList = this.getFullTxList()
|
||||
return fullTxList.filter((txMeta) => txMeta.metamaskNetworkId === network)
|
||||
}
|
||||
|
||||
/**
|
||||
@returns {array} of all the txMetas in store
|
||||
*/
|
||||
getFullTxList () {
|
||||
return this.store.getState().transactions
|
||||
}
|
||||
|
||||
// Returns the tx list
|
||||
/**
|
||||
@returns {array} the tx list whos status is unapproved
|
||||
*/
|
||||
getUnapprovedTxList () {
|
||||
const txList = this.getTxsByMetaData('status', 'unapproved')
|
||||
return txList.reduce((result, tx) => {
|
||||
@ -57,18 +80,35 @@ module.exports = class TransactionStateManager extends EventEmitter {
|
||||
}, {})
|
||||
}
|
||||
|
||||
/**
|
||||
@param address {string} - hex prefixed address to sort the txMetas for [optional]
|
||||
@returns {array} the tx list whos status is submitted
|
||||
*/
|
||||
getPendingTransactions (address) {
|
||||
const opts = { status: 'submitted' }
|
||||
if (address) opts.from = address
|
||||
return this.getFilteredTxList(opts)
|
||||
}
|
||||
|
||||
/**
|
||||
@param address {string} - hex prefixed address to sort the txMetas for [optional]
|
||||
@returns {array} the tx list whos status is confirmed
|
||||
*/
|
||||
getConfirmedTransactions (address) {
|
||||
const opts = { status: 'confirmed' }
|
||||
if (address) opts.from = address
|
||||
return this.getFilteredTxList(opts)
|
||||
}
|
||||
|
||||
/**
|
||||
Adds the txMeta to the list of transactions in the store.
|
||||
if the list is over txHistoryLimit it will remove a transaction that
|
||||
is in its final state
|
||||
it will allso add the key `history` to the txMeta with the snap shot of the original
|
||||
object
|
||||
@param txMeta {object}
|
||||
@returns {object} the txMeta
|
||||
*/
|
||||
addTx (txMeta) {
|
||||
this.once(`${txMeta.id}:signed`, function (txId) {
|
||||
this.removeAllListeners(`${txMeta.id}:rejected`)
|
||||
@ -93,7 +133,7 @@ module.exports = class TransactionStateManager extends EventEmitter {
|
||||
// not tx's that are pending or unapproved
|
||||
if (txCount > txHistoryLimit - 1) {
|
||||
const index = transactions.findIndex((metaTx) => {
|
||||
return this.getFinalStates().includes(metaTx.status)
|
||||
return getFinalStates().includes(metaTx.status)
|
||||
})
|
||||
if (index !== -1) {
|
||||
transactions.splice(index, 1)
|
||||
@ -103,12 +143,21 @@ module.exports = class TransactionStateManager extends EventEmitter {
|
||||
this._saveTxList(transactions)
|
||||
return txMeta
|
||||
}
|
||||
// gets tx by Id and returns it
|
||||
/**
|
||||
@param txId {number}
|
||||
@returns {object} the txMeta who matches the given id if none found
|
||||
for the network returns undefined
|
||||
*/
|
||||
getTx (txId) {
|
||||
const txMeta = this.getTxsByMetaData('id', txId)[0]
|
||||
return txMeta
|
||||
}
|
||||
|
||||
/**
|
||||
updates the txMeta in the list and adds a history entry
|
||||
@param txMeta {object} - the txMeta to update
|
||||
@param note {string} - a not about the update for history
|
||||
*/
|
||||
updateTx (txMeta, note) {
|
||||
// validate txParams
|
||||
if (txMeta.txParams) {
|
||||
@ -136,15 +185,22 @@ module.exports = class TransactionStateManager extends EventEmitter {
|
||||
}
|
||||
|
||||
|
||||
// merges txParams obj onto txData.txParams
|
||||
// use extend to ensure that all fields are filled
|
||||
/**
|
||||
merges txParams obj onto txMeta.txParams
|
||||
use extend to ensure that all fields are filled
|
||||
@param txId {number} - the id of the txMeta
|
||||
@param txParams {object} - the updated txParams
|
||||
*/
|
||||
updateTxParams (txId, txParams) {
|
||||
const txMeta = this.getTx(txId)
|
||||
txMeta.txParams = extend(txMeta.txParams, txParams)
|
||||
this.updateTx(txMeta, `txStateManager#updateTxParams`)
|
||||
}
|
||||
|
||||
// validates txParams members by type
|
||||
/**
|
||||
validates txParams members by type
|
||||
@param txParams {object} - txParams to validate
|
||||
*/
|
||||
validateTxParams (txParams) {
|
||||
Object.keys(txParams).forEach((key) => {
|
||||
const value = txParams[key]
|
||||
@ -161,17 +217,18 @@ module.exports = class TransactionStateManager extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
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
|
||||
/**
|
||||
@param opts {object} - an object of fields to search for eg:<br>
|
||||
let <code>thingsToLookFor = {<br>
|
||||
to: '0x0..',<br>
|
||||
from: '0x0..',<br>
|
||||
status: 'signed',<br>
|
||||
err: undefined,<br>
|
||||
}<br></code>
|
||||
@returns a {array} of txMeta with all
|
||||
options matching
|
||||
|
||||
*/
|
||||
/*
|
||||
****************HINT****************
|
||||
| `err: undefined` is like looking |
|
||||
| for a tx with no err |
|
||||
@ -192,7 +249,14 @@ module.exports = class TransactionStateManager extends EventEmitter {
|
||||
})
|
||||
return filteredTxList
|
||||
}
|
||||
/**
|
||||
|
||||
@param key {string} - the key to check
|
||||
@param value - the value your looking for
|
||||
@param txList {array} - [optional] the list to search. default is the txList
|
||||
from txStateManager#getTxList
|
||||
@returns {array} a list of txMetas who matches the search params
|
||||
*/
|
||||
getTxsByMetaData (key, value, txList = this.getTxList()) {
|
||||
return txList.filter((txMeta) => {
|
||||
if (txMeta.txParams[key]) {
|
||||
@ -205,33 +269,51 @@ module.exports = class TransactionStateManager extends EventEmitter {
|
||||
|
||||
// get::set status
|
||||
|
||||
// should return the status of the tx.
|
||||
/**
|
||||
@param txId {number} - the txMeta Id
|
||||
@return {string} the status of the tx.
|
||||
*/
|
||||
getTxStatus (txId) {
|
||||
const txMeta = this.getTx(txId)
|
||||
return txMeta.status
|
||||
}
|
||||
|
||||
// should update the status of the tx to 'rejected'.
|
||||
/**
|
||||
should update the status of the tx to 'rejected'.
|
||||
@param txId {number} - the txMeta Id
|
||||
*/
|
||||
setTxStatusRejected (txId) {
|
||||
this._setTxStatus(txId, 'rejected')
|
||||
}
|
||||
|
||||
// should update the status of the tx to 'unapproved'.
|
||||
/**
|
||||
should update the status of the tx to 'unapproved'.
|
||||
@param txId {number} - the txMeta Id
|
||||
*/
|
||||
setTxStatusUnapproved (txId) {
|
||||
this._setTxStatus(txId, 'unapproved')
|
||||
}
|
||||
// should update the status of the tx to 'approved'.
|
||||
/**
|
||||
should update the status of the tx to 'approved'.
|
||||
@param txId {number} - the txMeta Id
|
||||
*/
|
||||
setTxStatusApproved (txId) {
|
||||
this._setTxStatus(txId, 'approved')
|
||||
}
|
||||
|
||||
// should update the status of the tx to 'signed'.
|
||||
/**
|
||||
should update the status of the tx to 'signed'.
|
||||
@param txId {number} - the txMeta Id
|
||||
*/
|
||||
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
|
||||
/**
|
||||
should update the status of the tx to 'submitted'.
|
||||
and add a time stamp for when it was called
|
||||
@param txId {number} - the txMeta Id
|
||||
*/
|
||||
setTxStatusSubmitted (txId) {
|
||||
const txMeta = this.getTx(txId)
|
||||
txMeta.submittedTime = (new Date()).getTime()
|
||||
@ -239,17 +321,29 @@ module.exports = class TransactionStateManager extends EventEmitter {
|
||||
this._setTxStatus(txId, 'submitted')
|
||||
}
|
||||
|
||||
// should update the status of the tx to 'confirmed'.
|
||||
/**
|
||||
should update the status of the tx to 'confirmed'.
|
||||
@param txId {number} - the txMeta Id
|
||||
*/
|
||||
setTxStatusConfirmed (txId) {
|
||||
this._setTxStatus(txId, 'confirmed')
|
||||
}
|
||||
|
||||
// should update the status dropped
|
||||
/**
|
||||
should update the status of the tx to 'dropped'.
|
||||
@param txId {number} - the txMeta Id
|
||||
*/
|
||||
setTxStatusDropped (txId) {
|
||||
this._setTxStatus(txId, 'dropped')
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
should update the status of the tx to 'failed'.
|
||||
and put the error on the txMeta
|
||||
@param txId {number} - the txMeta Id
|
||||
@param err {erroObject} - error object
|
||||
*/
|
||||
setTxStatusFailed (txId, err) {
|
||||
const txMeta = this.getTx(txId)
|
||||
txMeta.err = {
|
||||
@ -260,16 +354,11 @@ module.exports = class TransactionStateManager extends EventEmitter {
|
||||
this._setTxStatus(txId, 'failed')
|
||||
}
|
||||
|
||||
// returns an array of states that can be considered final
|
||||
getFinalStates () {
|
||||
return [
|
||||
'rejected', // the user has responded no!
|
||||
'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
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
Removes transaction from the given address for the current network
|
||||
from the txList
|
||||
@param address {string} - hex string of the from address on the txParams to remove
|
||||
*/
|
||||
wipeTransactions (address) {
|
||||
// network only tx
|
||||
const txs = this.getFullTxList()
|
||||
@ -295,6 +384,14 @@ module.exports = class TransactionStateManager extends EventEmitter {
|
||||
// - `'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
|
||||
|
||||
/**
|
||||
@param txId {number} - the txMeta Id
|
||||
@param status {string} - the status to set on the txMeta
|
||||
@emits tx:status-update - passes txId and status
|
||||
@emits ${txMeta.id}:finished - if it is a finished state. Passes the txMeta
|
||||
@emits update:badge
|
||||
*/
|
||||
_setTxStatus (txId, status) {
|
||||
const txMeta = this.getTx(txId)
|
||||
txMeta.status = status
|
||||
@ -307,9 +404,14 @@ module.exports = class TransactionStateManager extends EventEmitter {
|
||||
this.emit('update:badge')
|
||||
}
|
||||
|
||||
// Saves the new/updated txList.
|
||||
/**
|
||||
Saves the new/updated txList.
|
||||
@param transactions {array} - the list of transactions to save
|
||||
*/
|
||||
// Function is intended only for internal use
|
||||
_saveTxList (transactions) {
|
||||
this.store.updateState({ transactions })
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TransactionStateManager
|
||||
|
BIN
docs/transaction-flow.png
Normal file
BIN
docs/transaction-flow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 138 KiB |
Loading…
Reference in New Issue
Block a user