aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app/helpers/utils/transactions.util.js
diff options
context:
space:
mode:
Diffstat (limited to 'ui/app/helpers/utils/transactions.util.js')
-rw-r--r--ui/app/helpers/utils/transactions.util.js179
1 files changed, 179 insertions, 0 deletions
diff --git a/ui/app/helpers/utils/transactions.util.js b/ui/app/helpers/utils/transactions.util.js
new file mode 100644
index 000000000..edf2e24f6
--- /dev/null
+++ b/ui/app/helpers/utils/transactions.util.js
@@ -0,0 +1,179 @@
+import ethUtil from 'ethereumjs-util'
+import MethodRegistry from 'eth-method-registry'
+import abi from 'human-standard-token-abi'
+import abiDecoder from 'abi-decoder'
+import {
+ TRANSACTION_TYPE_CANCEL,
+ TRANSACTION_STATUS_CONFIRMED,
+} from '../../../../app/scripts/controllers/transactions/enums'
+
+import {
+ TOKEN_METHOD_TRANSFER,
+ TOKEN_METHOD_APPROVE,
+ TOKEN_METHOD_TRANSFER_FROM,
+ SEND_ETHER_ACTION_KEY,
+ DEPLOY_CONTRACT_ACTION_KEY,
+ APPROVE_ACTION_KEY,
+ SEND_TOKEN_ACTION_KEY,
+ TRANSFER_FROM_ACTION_KEY,
+ SIGNATURE_REQUEST_KEY,
+ CONTRACT_INTERACTION_KEY,
+ CANCEL_ATTEMPT_ACTION_KEY,
+} from '../constants/transactions'
+
+import { addCurrencies } from './conversion-util'
+
+abiDecoder.addABI(abi)
+
+export function getTokenData (data = '') {
+ return abiDecoder.decodeMethod(data)
+}
+
+const registry = new MethodRegistry({ provider: global.ethereumProvider })
+
+/**
+ * Attempts to return the method data from the MethodRegistry library, if the method exists in the
+ * registry. Otherwise, returns an empty object.
+ * @param {string} data - The hex data (@code txParams.data) of a transaction
+ * @returns {Object}
+ */
+export async function getMethodData (data = '') {
+ const prefixedData = ethUtil.addHexPrefix(data)
+ const fourBytePrefix = prefixedData.slice(0, 10)
+ const sig = await registry.lookup(fourBytePrefix)
+
+ if (!sig) {
+ return {}
+ }
+
+ const parsedResult = registry.parse(sig)
+
+ return {
+ name: parsedResult.name,
+ params: parsedResult.args,
+ }
+}
+
+export function isConfirmDeployContract (txData = {}) {
+ const { txParams = {} } = txData
+ return !txParams.to
+}
+
+/**
+ * Returns four-byte method signature from data
+ *
+ * @param {string} data - The hex data (@code txParams.data) of a transaction
+ * @returns {string} - The four-byte method signature
+ */
+export function getFourBytePrefix (data = '') {
+ const prefixedData = ethUtil.addHexPrefix(data)
+ const fourBytePrefix = prefixedData.slice(0, 10)
+ return fourBytePrefix
+}
+
+/**
+ * Returns the action of a transaction as a key to be passed into the translator.
+ * @param {Object} transaction - txData object
+ * @param {Object} methodData - Data returned from eth-method-registry
+ * @returns {string|undefined}
+ */
+export async function getTransactionActionKey (transaction, methodData) {
+ const { txParams: { data, to } = {}, msgParams, type } = transaction
+
+ if (type === 'cancel') {
+ return CANCEL_ATTEMPT_ACTION_KEY
+ }
+
+ if (msgParams) {
+ return SIGNATURE_REQUEST_KEY
+ }
+
+ if (isConfirmDeployContract(transaction)) {
+ return DEPLOY_CONTRACT_ACTION_KEY
+ }
+
+ if (data) {
+ const toSmartContract = await isSmartContractAddress(to)
+
+ if (!toSmartContract) {
+ return SEND_ETHER_ACTION_KEY
+ }
+
+ const { name } = methodData
+ const methodName = name && name.toLowerCase()
+
+ if (!methodName) {
+ return CONTRACT_INTERACTION_KEY
+ }
+
+ switch (methodName) {
+ case TOKEN_METHOD_TRANSFER:
+ return SEND_TOKEN_ACTION_KEY
+ case TOKEN_METHOD_APPROVE:
+ return APPROVE_ACTION_KEY
+ case TOKEN_METHOD_TRANSFER_FROM:
+ return TRANSFER_FROM_ACTION_KEY
+ default:
+ return undefined
+ }
+ } else {
+ return SEND_ETHER_ACTION_KEY
+ }
+}
+
+export function getLatestSubmittedTxWithNonce (transactions = [], nonce = '0x0') {
+ if (!transactions.length) {
+ return {}
+ }
+
+ return transactions.reduce((acc, current) => {
+ const { submittedTime, txParams: { nonce: currentNonce } = {} } = current
+
+ if (currentNonce === nonce) {
+ return acc.submittedTime
+ ? submittedTime > acc.submittedTime ? current : acc
+ : current
+ } else {
+ return acc
+ }
+ }, {})
+}
+
+export async function isSmartContractAddress (address) {
+ const code = await global.eth.getCode(address)
+ // Geth will return '0x', and ganache-core v2.2.1 will return '0x0'
+ const codeIsEmpty = !code || code === '0x' || code === '0x0'
+ return !codeIsEmpty
+}
+
+export function sumHexes (...args) {
+ const total = args.reduce((acc, base) => {
+ return addCurrencies(acc, base, {
+ toNumericBase: 'hex',
+ })
+ })
+
+ return ethUtil.addHexPrefix(total)
+}
+
+/**
+ * Returns a status key for a transaction. Requires parsing the txMeta.txReceipt on top of
+ * txMeta.status because txMeta.status does not reflect on-chain errors.
+ * @param {Object} transaction - The txMeta object of a transaction.
+ * @param {Object} transaction.txReceipt - The transaction receipt.
+ * @returns {string}
+ */
+export function getStatusKey (transaction) {
+ const { txReceipt: { status: receiptStatus } = {}, type, status } = transaction
+
+ // There was an on-chain failure
+ if (receiptStatus === '0x0') {
+ return 'failed'
+ }
+
+ if (status === TRANSACTION_STATUS_CONFIRMED && type === TRANSACTION_TYPE_CANCEL) {
+ return 'cancelled'
+ }
+
+ return transaction.status
+}