aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app/components/transaction-activity-log/transaction-activity-log.util.js
diff options
context:
space:
mode:
authorAlexander Tseung <alextsg@users.noreply.github.com>2018-12-10 04:48:06 +0800
committerGitHub <noreply@github.com>2018-12-10 04:48:06 +0800
commitd8ab9cc002c10757b7382a174dafff7a0247e307 (patch)
treed0a46ac3ca2334ddec2ee240214d67a8122e81b7 /ui/app/components/transaction-activity-log/transaction-activity-log.util.js
parent575fb607c3b8deea831aa28293303991b3f6be29 (diff)
downloadtangerine-wallet-browser-d8ab9cc002c10757b7382a174dafff7a0247e307.tar.gz
tangerine-wallet-browser-d8ab9cc002c10757b7382a174dafff7a0247e307.tar.zst
tangerine-wallet-browser-d8ab9cc002c10757b7382a174dafff7a0247e307.zip
Group transactions by nonce (#5886)
Diffstat (limited to 'ui/app/components/transaction-activity-log/transaction-activity-log.util.js')
-rw-r--r--ui/app/components/transaction-activity-log/transaction-activity-log.util.js199
1 files changed, 165 insertions, 34 deletions
diff --git a/ui/app/components/transaction-activity-log/transaction-activity-log.util.js b/ui/app/components/transaction-activity-log/transaction-activity-log.util.js
index 16597ae1a..6206a4678 100644
--- a/ui/app/components/transaction-activity-log/transaction-activity-log.util.js
+++ b/ui/app/components/transaction-activity-log/transaction-activity-log.util.js
@@ -1,28 +1,39 @@
+import { getHexGasTotal } from '../../helpers/confirm-transaction/util'
+
// path constants
const STATUS_PATH = '/status'
const GAS_PRICE_PATH = '/txParams/gasPrice'
-
-// status constants
-const UNAPPROVED_STATUS = 'unapproved'
-const SUBMITTED_STATUS = 'submitted'
-const CONFIRMED_STATUS = 'confirmed'
-const DROPPED_STATUS = 'dropped'
+const GAS_LIMIT_PATH = '/txParams/gas'
// op constants
const REPLACE_OP = 'replace'
-// event constants
-const TRANSACTION_CREATED_EVENT = 'transactionCreated'
-const TRANSACTION_UPDATED_GAS_EVENT = 'transactionUpdatedGas'
-const TRANSACTION_SUBMITTED_EVENT = 'transactionSubmitted'
-const TRANSACTION_CONFIRMED_EVENT = 'transactionConfirmed'
-const TRANSACTION_DROPPED_EVENT = 'transactionDropped'
-const TRANSACTION_UPDATED_EVENT = 'transactionUpdated'
-const TRANSACTION_ERRORED_EVENT = 'transactionErrored'
+import {
+ // event constants
+ TRANSACTION_CREATED_EVENT,
+ TRANSACTION_SUBMITTED_EVENT,
+ TRANSACTION_RESUBMITTED_EVENT,
+ TRANSACTION_CONFIRMED_EVENT,
+ TRANSACTION_DROPPED_EVENT,
+ TRANSACTION_UPDATED_EVENT,
+ TRANSACTION_ERRORED_EVENT,
+ TRANSACTION_CANCEL_ATTEMPTED_EVENT,
+ TRANSACTION_CANCEL_SUCCESS_EVENT,
+ // status constants
+ SUBMITTED_STATUS,
+ CONFIRMED_STATUS,
+ DROPPED_STATUS,
+} from './transaction-activity-log.constants'
+
+import {
+ TRANSACTION_TYPE_CANCEL,
+ TRANSACTION_TYPE_RETRY,
+} from '../../../../app/scripts/controllers/transactions/enums'
const eventPathsHash = {
[STATUS_PATH]: true,
[GAS_PRICE_PATH]: true,
+ [GAS_LIMIT_PATH]: true,
}
const statusHash = {
@@ -31,22 +42,39 @@ const statusHash = {
[DROPPED_STATUS]: TRANSACTION_DROPPED_EVENT,
}
-function eventCreator (eventKey, timestamp, value) {
- return {
- eventKey,
- timestamp,
- value,
- }
-}
-
-export function getActivities (transaction) {
- const { history = [], txReceipt: { status } = {} } = transaction
-
- const historyActivities = history.reduce((acc, base) => {
+/**
+ * @name getActivities
+ * @param {Object} transaction - txMeta object
+ * @param {boolean} isFirstTransaction - True if the transaction is the first created transaction
+ * in the list of transactions with the same nonce. If so, we use this transaction to create the
+ * transactionCreated activity.
+ * @returns {Array}
+ */
+export function getActivities (transaction, isFirstTransaction = false) {
+ const { id, hash, history = [], txReceipt: { status } = {}, type } = transaction
+
+ let cachedGasLimit = '0x0'
+ let cachedGasPrice = '0x0'
+
+ const historyActivities = history.reduce((acc, base, index) => {
// First history item should be transaction creation
- if (!Array.isArray(base) && base.status === UNAPPROVED_STATUS && base.txParams) {
- const { time, txParams: { value } = {} } = base
- return acc.concat(eventCreator(TRANSACTION_CREATED_EVENT, time, value))
+ if (index === 0 && !Array.isArray(base) && base.txParams) {
+ const { time: timestamp, txParams: { value, gas = '0x0', gasPrice = '0x0' } = {} } = base
+ // The cached gas limit and gas price are used to display the gas fee in the activity log. We
+ // need to cache these values because the status update history events don't provide us with
+ // the latest gas limit and gas price.
+ cachedGasLimit = gas
+ cachedGasPrice = gasPrice
+
+ if (isFirstTransaction) {
+ return acc.concat({
+ id,
+ hash,
+ eventKey: TRANSACTION_CREATED_EVENT,
+ timestamp,
+ value,
+ })
+ }
// An entry in the history may be an array of more sub-entries.
} else if (Array.isArray(base)) {
const events = []
@@ -60,20 +88,69 @@ export function getActivities (transaction) {
if (path in eventPathsHash && op === REPLACE_OP) {
switch (path) {
case STATUS_PATH: {
+ const gasFee = getHexGasTotal({ gasLimit: cachedGasLimit, gasPrice: cachedGasPrice })
+
if (value in statusHash) {
- events.push(eventCreator(statusHash[value], timestamp))
+ let eventKey = statusHash[value]
+
+ // If the status is 'submitted', we need to determine whether the event is a
+ // transaction retry or a cancellation attempt.
+ if (value === SUBMITTED_STATUS) {
+ if (type === TRANSACTION_TYPE_RETRY) {
+ eventKey = TRANSACTION_RESUBMITTED_EVENT
+ } else if (type === TRANSACTION_TYPE_CANCEL) {
+ eventKey = TRANSACTION_CANCEL_ATTEMPTED_EVENT
+ }
+ } else if (value === CONFIRMED_STATUS) {
+ if (type === TRANSACTION_TYPE_CANCEL) {
+ eventKey = TRANSACTION_CANCEL_SUCCESS_EVENT
+ }
+ }
+
+ events.push({
+ id,
+ hash,
+ eventKey,
+ timestamp,
+ value: gasFee,
+ })
}
break
}
- case GAS_PRICE_PATH: {
- events.push(eventCreator(TRANSACTION_UPDATED_GAS_EVENT, timestamp, value))
+ // If the gas price or gas limit has been changed, we update the gasFee of the
+ // previously submitted event. These events happen when the gas limit and gas price is
+ // changed at the confirm screen.
+ case GAS_PRICE_PATH:
+ case GAS_LIMIT_PATH: {
+ const lastEvent = events[events.length - 1] || {}
+ const { lastEventKey } = lastEvent
+
+ if (path === GAS_LIMIT_PATH) {
+ cachedGasLimit = value
+ } else if (path === GAS_PRICE_PATH) {
+ cachedGasPrice = value
+ }
+
+ if (lastEventKey === TRANSACTION_SUBMITTED_EVENT ||
+ lastEventKey === TRANSACTION_RESUBMITTED_EVENT) {
+ lastEvent.value = getHexGasTotal({
+ gasLimit: cachedGasLimit,
+ gasPrice: cachedGasPrice,
+ })
+ }
+
break
}
default: {
- events.push(eventCreator(TRANSACTION_UPDATED_EVENT, timestamp))
+ events.push({
+ id,
+ hash,
+ eventKey: TRANSACTION_UPDATED_EVENT,
+ timestamp,
+ })
}
}
}
@@ -88,6 +165,60 @@ export function getActivities (transaction) {
// If txReceipt.status is '0x0', that means that an on-chain error occured for the transaction,
// so we add an error entry to the Activity Log.
return status === '0x0'
- ? historyActivities.concat(eventCreator(TRANSACTION_ERRORED_EVENT))
+ ? historyActivities.concat({ id, hash, eventKey: TRANSACTION_ERRORED_EVENT })
: historyActivities
}
+
+/**
+ * @description Removes "Transaction dropped" activities from a list of sorted activities if one of
+ * the transactions has been confirmed. Typically, if multiple transactions have the same nonce,
+ * once one transaction is confirmed, the rest are dropped. In this case, we don't want to show
+ * multiple "Transaction dropped" activities, and instead want to show a single "Transaction
+ * confirmed".
+ * @param {Array} activities - List of sorted activities generated from the getActivities function.
+ * @returns {Array}
+ */
+function filterSortedActivities (activities) {
+ const filteredActivities = []
+ const hasConfirmedActivity = Boolean(activities.find(({ eventKey }) => (
+ eventKey === TRANSACTION_CONFIRMED_EVENT || eventKey === TRANSACTION_CANCEL_SUCCESS_EVENT
+ )))
+ let addedDroppedActivity = false
+
+ activities.forEach(activity => {
+ if (activity.eventKey === TRANSACTION_DROPPED_EVENT) {
+ if (!hasConfirmedActivity && !addedDroppedActivity) {
+ filteredActivities.push(activity)
+ addedDroppedActivity = true
+ }
+ } else {
+ filteredActivities.push(activity)
+ }
+ })
+
+ return filteredActivities
+}
+
+/**
+ * Combines the histories of an array of transactions into a single array.
+ * @param {Array} transactions - Array of txMeta transaction objects.
+ * @returns {Array}
+ */
+export function combineTransactionHistories (transactions = []) {
+ if (!transactions.length) {
+ return []
+ }
+
+ const activities = []
+
+ transactions.forEach((transaction, index) => {
+ // The first transaction should be the transaction with the earliest submittedTime. We show the
+ // 'created' and 'submitted' activities here. All subsequent transactions will use 'resubmitted'
+ // instead.
+ const transactionActivities = getActivities(transaction, index === 0)
+ activities.push(...transactionActivities)
+ })
+
+ const sortedActivities = activities.sort((a, b) => a.timestamp - b.timestamp)
+ return filterSortedActivities(sortedActivities)
+}