diff --git a/package.json b/package.json index b777b1733..2639d6071 100644 --- a/package.json +++ b/package.json @@ -149,7 +149,6 @@ "pump": "^3.0.0", "punycode": "^2.1.1", "qrcode-generator": "1.4.1", - "ramda": "^0.24.1", "react": "^16.12.0", "react-dnd": "^3.0.2", "react-dnd-html5-backend": "^7.4.4", diff --git a/ui/app/components/app/dropdowns/network-dropdown.js b/ui/app/components/app/dropdowns/network-dropdown.js index 20f011755..111309a40 100644 --- a/ui/app/components/app/dropdowns/network-dropdown.js +++ b/ui/app/components/app/dropdowns/network-dropdown.js @@ -6,7 +6,6 @@ import { compose } from 'redux' import * as actions from '../../../store/actions' import { Dropdown, DropdownMenuItem } from './components/dropdown' import NetworkDropdownIcon from './components/network-dropdown-icon' -import R from 'ramda' import { NETWORKS_ROUTE } from '../../../helpers/constants/routes' // classes from nodes of the toggle element. @@ -219,7 +218,7 @@ class NetworkDropdown extends Component { onClickOutside={(event) => { const { classList } = event.target const isInClassList = (className) => classList.contains(className) - const notToggleElementIndex = R.findIndex(isInClassList)(notToggleElementClassnames) + const notToggleElementIndex = notToggleElementClassnames.findIndex(isInClassList) if (notToggleElementIndex === -1) { this.props.hideNetworkDropdown() diff --git a/ui/app/components/app/dropdowns/simple-dropdown.js b/ui/app/components/app/dropdowns/simple-dropdown.js index 06cf3c631..a8de50851 100644 --- a/ui/app/components/app/dropdowns/simple-dropdown.js +++ b/ui/app/components/app/dropdowns/simple-dropdown.js @@ -1,7 +1,6 @@ import classnames from 'classnames' import PropTypes from 'prop-types' import React, { Component } from 'react' -import R from 'ramda' class SimpleDropdown extends Component { static propTypes = { @@ -18,7 +17,7 @@ class SimpleDropdown extends Component { getDisplayValue () { const { selectedOption, options } = this.props const matchesOption = (option) => option.value === selectedOption - const matchingOption = R.find(matchesOption)(options) + const matchingOption = options.find(matchesOption) return matchingOption ? matchingOption.displayValue || matchingOption.value : selectedOption diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js index 098641f69..291ec2443 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js @@ -1,5 +1,4 @@ import { connect } from 'react-redux' -import { pipe, partialRight } from 'ramda' import GasModalPageContainer from './gas-modal-page-container.component' import { hideModal, @@ -308,23 +307,18 @@ function calcCustomGasLimit (customGasLimitInHex) { } function addHexWEIsToRenderableEth (aHexWEI, bHexWEI) { - return pipe( - addHexWEIsToDec, - formatETHFee - )(aHexWEI, bHexWEI) + return formatETHFee(addHexWEIsToDec(aHexWEI, bHexWEI)) } -function subtractHexWEIsFromRenderableEth (aHexWEI, bHexWei) { - return pipe( - subtractHexWEIsToDec, - formatETHFee - )(aHexWEI, bHexWei) +function subtractHexWEIsFromRenderableEth (aHexWEI, bHexWEI) { + return formatETHFee(subtractHexWEIsToDec(aHexWEI, bHexWEI)) } function addHexWEIsToRenderableFiat (aHexWEI, bHexWEI, convertedCurrency, conversionRate) { - return pipe( - addHexWEIsToDec, - partialRight(ethTotalToConvertedCurrency, [convertedCurrency, conversionRate]), - partialRight(formatCurrency, [convertedCurrency]), - )(aHexWEI, bHexWEI) + const ethTotal = ethTotalToConvertedCurrency( + addHexWEIsToDec(aHexWEI, bHexWEI), + convertedCurrency, + conversionRate + ) + return formatCurrency(ethTotal, convertedCurrency) } diff --git a/ui/app/components/app/transaction-activity-log/transaction-activity-log.container.js b/ui/app/components/app/transaction-activity-log/transaction-activity-log.container.js index a7ab8a5d9..7e01e8745 100644 --- a/ui/app/components/app/transaction-activity-log/transaction-activity-log.container.js +++ b/ui/app/components/app/transaction-activity-log/transaction-activity-log.container.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux' -import R from 'ramda' +import { findLastIndex } from 'lodash' import TransactionActivityLog from './transaction-activity-log.component' import { conversionRateSelector, getNativeCurrency } from '../../../selectors' import { combineTransactionHistories } from './transaction-activity-log.util' @@ -27,8 +27,8 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { } = ownProps const activities = combineTransactionHistories(transactions) - const inlineRetryIndex = R.findLastIndex(matchesEventKey(TRANSACTION_RESUBMITTED_EVENT))(activities) - const inlineCancelIndex = R.findLastIndex(matchesEventKey(TRANSACTION_CANCEL_ATTEMPTED_EVENT))(activities) + const inlineRetryIndex = findLastIndex(activities, matchesEventKey(TRANSACTION_RESUBMITTED_EVENT)) + const inlineCancelIndex = findLastIndex(activities, matchesEventKey(TRANSACTION_CANCEL_ATTEMPTED_EVENT)) return { ...stateProps, diff --git a/ui/app/ducks/gas/gas.duck.js b/ui/app/ducks/gas/gas.duck.js index 8f0ddb306..79b9aed44 100644 --- a/ui/app/ducks/gas/gas.duck.js +++ b/ui/app/ducks/gas/gas.duck.js @@ -1,4 +1,4 @@ -import { clone, uniqBy, flatten } from 'ramda' +import { uniqBy, cloneDeep, flatten } from 'lodash' import BigNumber from 'bignumber.js' import { loadLocalStorageData, @@ -138,10 +138,10 @@ export default function reducer (state = initState, action) { case RESET_CUSTOM_DATA: return { ...state, - customData: clone(initState.customData), + customData: cloneDeep(initState.customData), } case RESET_CUSTOM_GAS_STATE: - return clone(initState) + return cloneDeep(initState) default: return state } @@ -393,7 +393,7 @@ export function fetchGasEstimates (blockTime) { .then((r) => r.json()) .then((r) => { const estimatedPricesAndTimes = r.map(({ expectedTime, expectedWait, gasprice }) => ({ expectedTime, expectedWait, gasprice })) - const estimatedTimeWithUniquePrices = uniqBy(({ expectedTime }) => expectedTime, estimatedPricesAndTimes) + const estimatedTimeWithUniquePrices = uniqBy(estimatedPricesAndTimes, ({ expectedTime }) => expectedTime) const withSupplementalTimeEstimates = flatten(estimatedTimeWithUniquePrices.map(({ expectedWait, gasprice }, i, arr) => { const next = arr[i + 1] diff --git a/ui/app/helpers/utils/conversion-util.js b/ui/app/helpers/utils/conversion-util.js index b65c831af..1b4f89ed7 100644 --- a/ui/app/helpers/utils/conversion-util.js +++ b/ui/app/helpers/utils/conversion-util.js @@ -17,9 +17,8 @@ * @returns {(number | string | BN)} * * The utility passes value along with the options as a single object to the `converter` function. -* `converter` uses Ramda.js to apply a composition of conditional setters to the `value` property, depending -* on the accompanying options. Some of these conditional setters are selected via key-value maps, where -* the keys are specified in the options parameters and the values are setter functions. +* `converter` conditional modifies the supplied `value` property, depending +* on the accompanying options. */ import BigNumber from 'bignumber.js' @@ -27,11 +26,6 @@ import BigNumber from 'bignumber.js' import ethUtil, { stripHexPrefix } from 'ethereumjs-util' const BN = ethUtil.BN -import R from 'ramda' - -BigNumber.config({ - ROUNDING_MODE: BigNumber.ROUND_HALF_DOWN, -}) // Big Number Constants const BIG_NUMBER_WEI_MULTIPLIER = new BigNumber('1000000000000000000') @@ -60,60 +54,78 @@ const baseChange = { BN: (n) => new BN(n.toString(16)), } -// Individual Setters -const convert = R.invoker(1, 'times') -const round = R.invoker(2, 'round')(R.__, BigNumber.ROUND_HALF_DOWN) -const roundDown = R.invoker(2, 'round')(R.__, BigNumber.ROUND_DOWN) -const invertConversionRate = (conversionRate) => () => new BigNumber(1.0).div(conversionRate) -const decToBigNumberViaString = () => R.pipe(String, toBigNumber['dec']) +/** + * Defines the base type of numeric value + * @typedef {('hex' | 'dec' | 'BN')} NumericBase + */ -// Predicates -const fromAndToCurrencyPropsNotEqual = R.compose( - R.not, - R.eqBy(R.__, 'fromCurrency', 'toCurrency'), - R.flip(R.prop) -) +/** + * Defines which type of denomination a value is in + * @typedef {('WEI' | 'GWEI' | 'ETH')} EthDenomination + */ -// Lens -const valuePropertyLens = R.over(R.lensProp('value')) -const conversionRateLens = R.over(R.lensProp('conversionRate')) +/** + * Utility method to convert a value between denominations, formats and currencies. + * @param {Object} input + * @param {string | BigNumber} input.value + * @param {NumericBase} input.fromNumericBase + * @param {EthDenomination} [input.fromDenomination] + * @param {string} [input.fromCurrency] + * @param {NumericBase} input.toNumericBase + * @param {EthDenomination} [input.toDenomination] + * @param {string} [input.toCurrency] + * @param {number} [input.numberOfDecimals] + * @param {number} [input.conversionRate] + * @param {boolean} [input.invertConversionRate] + * @param {string} [input.roundDown] + */ +const converter = ({ + value, + fromNumericBase, + fromDenomination, + fromCurrency, + toNumericBase, + toDenomination, + toCurrency, + numberOfDecimals, + conversionRate, + invertConversionRate, + roundDown, +}) => { + let convertedValue = fromNumericBase ? toBigNumber[fromNumericBase](value) : value -// conditional conversionRate setting wrapper -const whenPredSetCRWithPropAndSetter = (pred, prop, setter) => R.when( - pred, - R.converge( - conversionRateLens, - [R.pipe(R.prop(prop), setter), R.identity] - ) -) + if (fromDenomination) { + convertedValue = toNormalizedDenomination[fromDenomination](convertedValue) + } -// conditional 'value' setting wrappers -const whenPredSetWithPropAndSetter = (pred, prop, setter) => R.when( - pred, - R.converge( - valuePropertyLens, - [R.pipe(R.prop(prop), setter), R.identity] - ) -) -const whenPropApplySetterMap = (prop, setterMap) => whenPredSetWithPropAndSetter( - R.prop(prop), - prop, - R.prop(R.__, setterMap) -) + if (fromCurrency !== toCurrency) { + if (conversionRate == null) { + throw new Error(`Converting from ${fromCurrency} to ${toCurrency} requires a conversionRate, but one was not provided`) + } + let rate = toBigNumber.dec(conversionRate) + if (invertConversionRate) { + rate = new BigNumber(1.0).div(conversionRate) + } + convertedValue = convertedValue.times(rate) + } -// Conversion utility function -const converter = R.pipe( - whenPredSetCRWithPropAndSetter(R.prop('conversionRate'), 'conversionRate', decToBigNumberViaString), - whenPredSetCRWithPropAndSetter(R.prop('invertConversionRate'), 'conversionRate', invertConversionRate), - whenPropApplySetterMap('fromNumericBase', toBigNumber), - whenPropApplySetterMap('fromDenomination', toNormalizedDenomination), - whenPredSetWithPropAndSetter(fromAndToCurrencyPropsNotEqual, 'conversionRate', convert), - whenPropApplySetterMap('toDenomination', toSpecifiedDenomination), - whenPredSetWithPropAndSetter(R.prop('numberOfDecimals'), 'numberOfDecimals', round), - whenPredSetWithPropAndSetter(R.prop('roundDown'), 'roundDown', roundDown), - whenPropApplySetterMap('toNumericBase', baseChange), - R.view(R.lensProp('value')) -) + if (toDenomination) { + convertedValue = toSpecifiedDenomination[toDenomination](convertedValue) + } + + if (numberOfDecimals) { + convertedValue = convertedValue.round(numberOfDecimals, BigNumber.ROUND_HALF_DOWN) + } + + if (roundDown) { + convertedValue = convertedValue.round(roundDown, BigNumber.ROUND_DOWN) + } + + if (toNumericBase) { + convertedValue = baseChange[toNumericBase](convertedValue) + } + return convertedValue +} const conversionUtil = (value, { fromCurrency = null, diff --git a/ui/app/helpers/utils/conversion-util.test.js b/ui/app/helpers/utils/conversion-util.test.js index 7b62faf32..719f7b6d9 100644 --- a/ui/app/helpers/utils/conversion-util.test.js +++ b/ui/app/helpers/utils/conversion-util.test.js @@ -1,6 +1,6 @@ import assert from 'assert' -import { addCurrencies } from './conversion-util' - +import { addCurrencies, conversionUtil } from './conversion-util' +import BigNumber from 'bignumber.js' describe('conversion utils', function () { describe('addCurrencies()', function () { @@ -19,4 +19,41 @@ describe('conversion utils', function () { assert.equal(result.toNumber(), 0.4444444444444444) }) }) + + describe('conversionUtil', function () { + it('Returns expected types', function () { + const conv1 = conversionUtil(1000000000000000000, { fromNumericBase: 'dec', toNumericBase: 'hex' }) + const conv2 = conversionUtil(1, { fromNumericBase: 'dec', fromDenomination: 'ETH', toDenomination: 'WEI' }) + assert(typeof conv1 === 'string', 'conversion 1 should return type string') + assert(conv2 instanceof BigNumber, 'conversion 2 should be a BigNumber') + }) + it('Converts from dec to hex', function () { + assert.equal(conversionUtil('1000000000000000000', { fromNumericBase: 'dec', toNumericBase: 'hex' }), 'de0b6b3a7640000') + assert.equal(conversionUtil('1500000000000000000', { fromNumericBase: 'dec', toNumericBase: 'hex' }), '14d1120d7b160000') + }) + it('Converts hex formatted numbers to dec', function () { + assert.equal(conversionUtil('0xde0b6b3a7640000', { fromNumericBase: 'hex', toNumericBase: 'dec' }), 1000000000000000000) + assert.equal(conversionUtil('0x14d1120d7b160000', { fromNumericBase: 'hex', toNumericBase: 'dec' }), 1500000000000000000) + }) + it('Converts WEI to ETH', function () { + assert.equal(conversionUtil('0xde0b6b3a7640000', { fromNumericBase: 'hex', toNumericBase: 'dec', fromDenomination: 'WEI', toDenomination: 'ETH' }), 1) + assert.equal(conversionUtil('0x14d1120d7b160000', { fromNumericBase: 'hex', toNumericBase: 'dec', fromDenomination: 'WEI', toDenomination: 'ETH' }), 1.5) + }) + it('Converts ETH to WEI', function () { + assert.equal(conversionUtil('1', { fromNumericBase: 'dec', fromDenomination: 'ETH', toDenomination: 'WEI' }), 1000000000000000000) + assert.equal(conversionUtil('1.5', { fromNumericBase: 'dec', fromDenomination: 'ETH', toDenomination: 'WEI' }), 1500000000000000000) + }) + it('Converts ETH to GWEI', function () { + assert.equal(conversionUtil('1', { fromNumericBase: 'dec', fromDenomination: 'ETH', toDenomination: 'GWEI' }), 1000000000) + assert.equal(conversionUtil('1.5', { fromNumericBase: 'dec', fromDenomination: 'ETH', toDenomination: 'GWEI' }), 1500000000) + }) + it('Converts ETH to USD', function () { + assert.equal(conversionUtil('1', { fromNumericBase: 'dec', toNumericBase: 'dec', toCurrency: 'usd', conversionRate: 468.58, numberOfDecimals: 2 }), 468.58) + assert.equal(conversionUtil('1.5', { fromNumericBase: 'dec', toNumericBase: 'dec', toCurrency: 'usd', conversionRate: 468.58, numberOfDecimals: 2 }), 702.87) + }) + it('Converts USD to ETH', function () { + assert.equal(conversionUtil('468.58', { fromNumericBase: 'dec', toNumericBase: 'dec', toCurrency: 'usd', conversionRate: 468.58, numberOfDecimals: 2, invertConversionRate: true }), 1) + assert.equal(conversionUtil('702.87', { fromNumericBase: 'dec', toNumericBase: 'dec', toCurrency: 'usd', conversionRate: 468.58, numberOfDecimals: 2, invertConversionRate: true }), 1.5) + }) + }) }) diff --git a/ui/app/pages/confirm-transaction/conf-tx.js b/ui/app/pages/confirm-transaction/conf-tx.js index da5345084..8e57a0fb0 100644 --- a/ui/app/pages/confirm-transaction/conf-tx.js +++ b/ui/app/pages/confirm-transaction/conf-tx.js @@ -6,7 +6,6 @@ import { compose } from 'redux' import * as actions from '../../store/actions' import txHelper from '../../../lib/tx-helper' import log from 'loglevel' -import R from 'ramda' import SignatureRequest from '../../components/app/signature-request' import SignatureRequestOriginal from '../../components/app/signature-request-original' import Loading from '../../components/ui/loading-screen' @@ -106,7 +105,7 @@ class ConfirmTxScreen extends Component { log.info(`rendering a combined ${unconfTxList.length} unconf msgs & txs`) return transactionId - ? R.find(({ id }) => id + '' === transactionId)(unconfTxList) + ? unconfTxList.find(({ id }) => id + '' === transactionId) : unconfTxList[index] } @@ -196,7 +195,7 @@ class ConfirmTxScreen extends Component { let prevTx if (transactionId) { - prevTx = R.find(({ id }) => id + '' === transactionId)(currentNetworkTxList) + prevTx = currentNetworkTxList.find(({ id }) => id + '' === transactionId) } else { const { index: prevIndex, unapprovedTxs: prevUnapprovedTxs } = prevProps const prevUnconfTxList = txHelper(prevUnapprovedTxs, {}, {}, {}, network) diff --git a/ui/app/selectors/custom-gas.js b/ui/app/selectors/custom-gas.js index 02ecfcb0c..e041269aa 100644 --- a/ui/app/selectors/custom-gas.js +++ b/ui/app/selectors/custom-gas.js @@ -1,4 +1,3 @@ -import { pipe, partialRight } from 'ramda' import { conversionUtil, multiplyCurrencies, @@ -128,21 +127,17 @@ export function basicPriceEstimateToETHTotal (estimate, gasLimit, numberOfDecima } export function getRenderableEthFee (estimate, gasLimit, numberOfDecimals = 9) { - return pipe( - (x) => conversionUtil(x, { fromNumericBase: 'dec', toNumericBase: 'hex' }), - partialRight(basicPriceEstimateToETHTotal, [gasLimit, numberOfDecimals]), - formatETHFee - )(estimate, gasLimit) + const value = conversionUtil(estimate, { fromNumericBase: 'dec', toNumericBase: 'hex' }) + const fee = basicPriceEstimateToETHTotal(value, gasLimit, numberOfDecimals) + return formatETHFee(fee) } export function getRenderableConvertedCurrencyFee (estimate, gasLimit, convertedCurrency, conversionRate) { - return pipe( - (x) => conversionUtil(x, { fromNumericBase: 'dec', toNumericBase: 'hex' }), - partialRight(basicPriceEstimateToETHTotal, [gasLimit]), - partialRight(ethTotalToConvertedCurrency, [convertedCurrency, conversionRate]), - partialRight(formatCurrency, [convertedCurrency]) - )(estimate, gasLimit, convertedCurrency, conversionRate) + const value = conversionUtil(estimate, { fromNumericBase: 'dec', toNumericBase: 'hex' }) + const fee = basicPriceEstimateToETHTotal(value, gasLimit) + const feeInCurrency = ethTotalToConvertedCurrency(fee, convertedCurrency, conversionRate) + return formatCurrency(feeInCurrency, convertedCurrency) } export function getTimeEstimateInSeconds (blockWaitEstimate) { @@ -179,10 +174,7 @@ export function formatTimeEstimate (totalSeconds, greaterThanMax, lessThanMin) { } export function getRenderableTimeEstimate (blockWaitEstimate) { - return pipe( - getTimeEstimateInSeconds, - formatTimeEstimate - )(blockWaitEstimate) + return formatTimeEstimate(getTimeEstimateInSeconds(blockWaitEstimate)) } export function priceEstimateToWei (priceEstimate) { @@ -196,11 +188,8 @@ export function priceEstimateToWei (priceEstimate) { } export function getGasPriceInHexWei (price) { - return pipe( - (x) => conversionUtil(x, { fromNumericBase: 'dec', toNumericBase: 'hex' }), - priceEstimateToWei, - addHexPrefix - )(price) + const value = conversionUtil(price, { fromNumericBase: 'dec', toNumericBase: 'hex' }) + return addHexPrefix(priceEstimateToWei(value)) } export function getRenderableBasicEstimateData (state, gasLimit) { diff --git a/yarn.lock b/yarn.lock index 2b661b8cc..0bd9070e4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22244,11 +22244,6 @@ ramda@^0.21.0: resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.21.0.tgz#a001abedb3ff61077d4ff1d577d44de77e8d0a35" integrity sha1-oAGr7bP/YQd9T/HVd9RN536NCjU= -ramda@^0.24.1: - version "0.24.1" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.24.1.tgz#c3b7755197f35b8dc3502228262c4c91ddb6b857" - integrity sha1-w7d1UZfzW43DUCIoJixMkd22uFc= - ramda@^0.26.1: version "0.26.1" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06"