Estimate gas using same algorithm as backend.

feature/default_network_editable
Dan 7 years ago
parent 166fda5877
commit 4f0b4eef50
  1. 19
      ui/app/actions.js
  2. 3
      ui/app/components/send_/send.component.js
  3. 3
      ui/app/components/send_/send.constants.js
  4. 5
      ui/app/components/send_/send.container.js
  5. 5
      ui/app/components/send_/send.selectors.js
  6. 63
      ui/app/components/send_/send.utils.js
  7. 2
      ui/app/components/send_/tests/send-component.test.js
  8. 7
      ui/app/components/send_/tests/send-container.test.js
  9. 1
      ui/app/components/send_/tests/send-selectors-test-data.js
  10. 10
      ui/app/components/send_/tests/send-selectors.test.js
  11. 122
      ui/app/components/send_/tests/send-utils.test.js
  12. 5
      ui/app/conversion-util.js

@ -4,7 +4,6 @@ const getBuyEthUrl = require('../../app/scripts/lib/buy-eth-url')
const { getTokenAddressFromTokenObject } = require('./util') const { getTokenAddressFromTokenObject } = require('./util')
const { const {
calcGasTotal, calcGasTotal,
getParamsForGasEstimate,
calcTokenBalance, calcTokenBalance,
estimateGas, estimateGas,
estimateGasPriceFromRecentBlocks, estimateGasPriceFromRecentBlocks,
@ -725,12 +724,24 @@ function setGasTotal (gasTotal) {
} }
} }
function updateGasData ({ recentBlocks, selectedAddress, selectedToken, data }) { function updateGasData ({
blockGasLimit,
data,
recentBlocks,
selectedAddress,
selectedToken,
to,
}) {
return (dispatch) => { return (dispatch) => {
const estimateGasParams = getParamsForGasEstimate(selectedAddress, selectedToken, data)
return Promise.all([ return Promise.all([
Promise.resolve(estimateGasPriceFromRecentBlocks(recentBlocks)), Promise.resolve(estimateGasPriceFromRecentBlocks(recentBlocks)),
estimateGas(estimateGasParams), estimateGas({
blockGasLimit,
data,
selectedAddress,
selectedToken,
to,
}),
]) ])
.then(([gasPrice, gas]) => { .then(([gasPrice, gas]) => {
dispatch(actions.setGasPrice(gasPrice)) dispatch(actions.setGasPrice(gasPrice))

@ -18,6 +18,7 @@ export default class SendTransactionScreen extends PersistentForm {
PropTypes.string, PropTypes.string,
PropTypes.number, PropTypes.number,
]), ]),
blockGasLimit: PropTypes.string,
conversionRate: PropTypes.number, conversionRate: PropTypes.number,
data: PropTypes.string, data: PropTypes.string,
editingTransactionId: PropTypes.string, editingTransactionId: PropTypes.string,
@ -40,6 +41,7 @@ export default class SendTransactionScreen extends PersistentForm {
updateGas () { updateGas () {
const { const {
blockGasLimit,
data, data,
editingTransactionId, editingTransactionId,
gasLimit, gasLimit,
@ -51,6 +53,7 @@ export default class SendTransactionScreen extends PersistentForm {
} = this.props } = this.props
updateAndSetGasTotal({ updateAndSetGasTotal({
blockGasLimit,
data, data,
editingTransactionId, editingTransactionId,
gasLimit, gasLimit,

@ -35,6 +35,8 @@ const ONE_GWEI_IN_WEI_HEX = ethUtil.addHexPrefix(conversionUtil('0x1', {
toNumericBase: 'hex', toNumericBase: 'hex',
})) }))
const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send.
module.exports = { module.exports = {
INSUFFICIENT_FUNDS_ERROR, INSUFFICIENT_FUNDS_ERROR,
INSUFFICIENT_TOKENS_ERROR, INSUFFICIENT_TOKENS_ERROR,
@ -48,5 +50,6 @@ module.exports = {
NEGATIVE_ETH_ERROR, NEGATIVE_ETH_ERROR,
ONE_GWEI_IN_WEI_HEX, ONE_GWEI_IN_WEI_HEX,
REQUIRED_ERROR, REQUIRED_ERROR,
SIMPLE_GAS_COST,
TOKEN_TRANSFER_FUNCTION_SIGNATURE, TOKEN_TRANSFER_FUNCTION_SIGNATURE,
} }

@ -4,6 +4,7 @@ import { withRouter } from 'react-router-dom'
import { compose } from 'recompose' import { compose } from 'recompose'
import { import {
getAmountConversionRate, getAmountConversionRate,
getBlockGasLimit,
getConversionRate, getConversionRate,
getCurrentNetwork, getCurrentNetwork,
getGasLimit, getGasLimit,
@ -45,6 +46,7 @@ function mapStateToProps (state) {
return { return {
amount: getSendAmount(state), amount: getSendAmount(state),
amountConversionRate: getAmountConversionRate(state), amountConversionRate: getAmountConversionRate(state),
blockGasLimit: getBlockGasLimit(state),
conversionRate: getConversionRate(state), conversionRate: getConversionRate(state),
data: generateTokenTransferData(selectedAddress, selectedToken), data: generateTokenTransferData(selectedAddress, selectedToken),
editingTransactionId: getSendEditingTransactionId(state), editingTransactionId: getSendEditingTransactionId(state),
@ -66,6 +68,7 @@ function mapStateToProps (state) {
function mapDispatchToProps (dispatch) { function mapDispatchToProps (dispatch) {
return { return {
updateAndSetGasTotal: ({ updateAndSetGasTotal: ({
blockGasLimit,
data, data,
editingTransactionId, editingTransactionId,
gasLimit, gasLimit,
@ -75,7 +78,7 @@ function mapDispatchToProps (dispatch) {
selectedToken, selectedToken,
}) => { }) => {
!editingTransactionId !editingTransactionId
? dispatch(updateGasData({ recentBlocks, selectedAddress, selectedToken, data })) ? dispatch(updateGasData({ recentBlocks, selectedAddress, selectedToken, data, blockGasLimit }))
: dispatch(setGasTotal(calcGasTotal(gasLimit, gasPrice))) : dispatch(setGasTotal(calcGasTotal(gasLimit, gasPrice)))
}, },
updateSendTokenBalance: ({ selectedToken, tokenContract, address }) => { updateSendTokenBalance: ({ selectedToken, tokenContract, address }) => {

@ -12,6 +12,7 @@ const selectors = {
// autoAddToBetaUI, // autoAddToBetaUI,
getAddressBook, getAddressBook,
getAmountConversionRate, getAmountConversionRate,
getBlockGasLimit,
getConversionRate, getConversionRate,
getConvertedCurrency, getConvertedCurrency,
getCurrentAccountWithSendEtherInfo, getCurrentAccountWithSendEtherInfo,
@ -89,6 +90,10 @@ function getAmountConversionRate (state) {
: getConversionRate(state) : getConversionRate(state)
} }
function getBlockGasLimit (state) {
return state.metamask.currentBlockGasLimit
}
function getConversionRate (state) { function getConversionRate (state) {
return state.metamask.conversionRate return state.metamask.conversionRate
} }

@ -13,18 +13,19 @@ const {
INSUFFICIENT_TOKENS_ERROR, INSUFFICIENT_TOKENS_ERROR,
NEGATIVE_ETH_ERROR, NEGATIVE_ETH_ERROR,
ONE_GWEI_IN_WEI_HEX, ONE_GWEI_IN_WEI_HEX,
SIMPLE_GAS_COST,
} = require('./send.constants') } = require('./send.constants')
const EthQuery = require('ethjs-query')
const abi = require('ethereumjs-abi') const abi = require('ethereumjs-abi')
module.exports = { module.exports = {
calcGasTotal, calcGasTotal,
calcTokenBalance,
doesAmountErrorRequireUpdate, doesAmountErrorRequireUpdate,
estimateGas, estimateGas,
estimateGasPriceFromRecentBlocks, estimateGasPriceFromRecentBlocks,
generateTokenTransferData, generateTokenTransferData,
getAmountErrorObject, getAmountErrorObject,
getParamsForGasEstimate,
calcTokenBalance,
isBalanceSufficient, isBalanceSufficient,
isTokenBalanceSufficient, isTokenBalanceSufficient,
} }
@ -142,24 +143,6 @@ function getAmountErrorObject ({
return { amount: amountError } return { amount: amountError }
} }
function getParamsForGasEstimate (selectedAddress, selectedToken, data) {
const { symbol } = selectedToken || {}
const estimatedGasParams = {
from: selectedAddress,
gas: '746a528800',
}
if (symbol) {
Object.assign(estimatedGasParams, { value: '0x0' })
}
if (data) {
Object.assign(estimatedGasParams, { data })
}
return estimatedGasParams
}
function calcTokenBalance ({ selectedToken, usersToken }) { function calcTokenBalance ({ selectedToken, usersToken }) {
const { decimals } = selectedToken || {} const { decimals } = selectedToken || {}
return calcTokenAmount(usersToken.balance.toString(), decimals) + '' return calcTokenAmount(usersToken.balance.toString(), decimals) + ''
@ -182,15 +165,40 @@ function doesAmountErrorRequireUpdate ({
return amountErrorRequiresUpdate return amountErrorRequiresUpdate
} }
function estimateGas (params = {}) { async function estimateGas ({ selectedAddress, selectedToken, data, blockGasLimit, to }) {
return new Promise((resolve, reject) => { const ethQuery = new EthQuery(global.ethereumProvider)
global.ethQuery.estimateGas(params, (err, data) => { const { symbol } = selectedToken || {}
if (err) { const estimatedGasParams = { from: selectedAddress }
return reject(err)
if (symbol) {
Object.assign(estimatedGasParams, { value: '0x0' })
}
if (data) {
Object.assign(estimatedGasParams, { data })
} }
return resolve(data) // if recipient has no code, gas is 21k max:
}) const hasRecipient = Boolean(to)
let code
if (hasRecipient) code = await ethQuery.getCode(to)
if (hasRecipient && (!code || code === '0x')) {
return SIMPLE_GAS_COST
}
estimatedGasParams.to = to
// if not, fall back to block gasLimit
estimatedGasParams.gas = multiplyCurrencies(blockGasLimit, 0.95, {
multiplicandBase: 16,
multiplierBase: 10,
roundDown: '0',
toNumericBase: 'hex',
}) })
// run tx
const estimatedGas = await ethQuery.estimateGas(estimatedGasParams)
return estimatedGas.toString(16)
} }
function generateTokenTransferData (selectedAddress, selectedToken) { function generateTokenTransferData (selectedAddress, selectedToken) {
@ -222,5 +230,6 @@ function estimateGasPriceFromRecentBlocks (recentBlocks) {
.sort(hexComparator)[0] .sort(hexComparator)[0]
}) })
.sort(hexComparator) .sort(hexComparator)
return lowestPrices[Math.floor(lowestPrices.length / 2)] return lowestPrices[Math.floor(lowestPrices.length / 2)]
} }

@ -32,6 +32,7 @@ describe.only('Send Component', function () {
wrapper = shallow(<SendTransactionScreen wrapper = shallow(<SendTransactionScreen
amount={'mockAmount'} amount={'mockAmount'}
amountConversionRate={'mockAmountConversionRate'} amountConversionRate={'mockAmountConversionRate'}
blockGasLimit={'mockBlockGasLimit'}
conversionRate={10} conversionRate={10}
data={'mockData'} data={'mockData'}
editingTransactionId={'mockEditingTransactionId'} editingTransactionId={'mockEditingTransactionId'}
@ -208,6 +209,7 @@ describe.only('Send Component', function () {
assert.deepEqual( assert.deepEqual(
propsMethodSpies.updateAndSetGasTotal.getCall(0).args[0], propsMethodSpies.updateAndSetGasTotal.getCall(0).args[0],
{ {
blockGasLimit: 'mockBlockGasLimit',
data: 'mockData', data: 'mockData',
editingTransactionId: 'mockEditingTransactionId', editingTransactionId: 'mockEditingTransactionId',
gasLimit: 'mockGasLimit', gasLimit: 'mockGasLimit',

@ -26,6 +26,7 @@ proxyquire('../send.container.js', {
'recompose': { compose: (arg1, arg2) => () => arg2() }, 'recompose': { compose: (arg1, arg2) => () => arg2() },
'./send.selectors': { './send.selectors': {
getAmountConversionRate: (s) => `mockAmountConversionRate:${s}`, getAmountConversionRate: (s) => `mockAmountConversionRate:${s}`,
getBlockGasLimit: (s) => `mockBlockGasLimit:${s}`,
getConversionRate: (s) => `mockConversionRate:${s}`, getConversionRate: (s) => `mockConversionRate:${s}`,
getCurrentNetwork: (s) => `mockNetwork:${s}`, getCurrentNetwork: (s) => `mockNetwork:${s}`,
getGasLimit: (s) => `mockGasLimit:${s}`, getGasLimit: (s) => `mockGasLimit:${s}`,
@ -58,6 +59,7 @@ describe('send container', () => {
assert.deepEqual(mapStateToProps('mockState'), { assert.deepEqual(mapStateToProps('mockState'), {
amount: 'mockAmount:mockState', amount: 'mockAmount:mockState',
amountConversionRate: 'mockAmountConversionRate:mockState', amountConversionRate: 'mockAmountConversionRate:mockState',
blockGasLimit: 'mockBlockGasLimit:mockState',
conversionRate: 'mockConversionRate:mockState', conversionRate: 'mockConversionRate:mockState',
data: 'mockData:mockSelectedAddress:mockStatemockSelectedToken:mockState', data: 'mockData:mockSelectedAddress:mockStatemockSelectedToken:mockState',
editingTransactionId: 'mockEditingTransactionId:mockState', editingTransactionId: 'mockEditingTransactionId:mockState',
@ -89,6 +91,7 @@ describe('send container', () => {
describe('updateAndSetGasTotal()', () => { describe('updateAndSetGasTotal()', () => {
const mockProps = { const mockProps = {
blockGasLimit: 'mockBlockGasLimit',
data: '0x1', data: '0x1',
editingTransactionId: '0x2', editingTransactionId: '0x2',
gasLimit: '0x3', gasLimit: '0x3',
@ -108,14 +111,14 @@ describe('send container', () => {
}) })
it('should dispatch an updateGasData action when editingTransactionId is falsy', () => { it('should dispatch an updateGasData action when editingTransactionId is falsy', () => {
const { selectedAddress, selectedToken, data, recentBlocks } = mockProps const { selectedAddress, selectedToken, data, recentBlocks, blockGasLimit } = mockProps
mapDispatchToPropsObject.updateAndSetGasTotal( mapDispatchToPropsObject.updateAndSetGasTotal(
Object.assign({}, mockProps, {editingTransactionId: false}) Object.assign({}, mockProps, {editingTransactionId: false})
) )
assert(dispatchSpy.calledOnce) assert(dispatchSpy.calledOnce)
assert.deepEqual( assert.deepEqual(
actionSpies.updateGasData.getCall(0).args[0], actionSpies.updateGasData.getCall(0).args[0],
{ selectedAddress, selectedToken, data, recentBlocks } { selectedAddress, selectedToken, data, recentBlocks, blockGasLimit }
) )
}) })
}) })

@ -22,6 +22,7 @@ module.exports = {
'name': 'Send Account 4', 'name': 'Send Account 4',
}, },
}, },
'currentBlockGasLimit': '0x4c1878',
'currentCurrency': 'USD', 'currentCurrency': 'USD',
'conversionRate': 1200.88200327, 'conversionRate': 1200.88200327,
'conversionDate': 1489013762, 'conversionDate': 1489013762,

@ -5,6 +5,7 @@ const {
accountsWithSendEtherInfoSelector, accountsWithSendEtherInfoSelector,
// autoAddToBetaUI, // autoAddToBetaUI,
getAddressBook, getAddressBook,
getBlockGasLimit,
getAmountConversionRate, getAmountConversionRate,
getConversionRate, getConversionRate,
getConvertedCurrency, getConvertedCurrency,
@ -135,6 +136,15 @@ describe('send selectors', () => {
}) })
}) })
describe('getBlockGasLimit', () => {
it('should return the current block gas limit', () => {
assert.deepEqual(
getBlockGasLimit(mockState),
'0x4c1878'
)
})
})
describe('getConversionRate()', () => { describe('getConversionRate()', () => {
it('should return the eth conversion rate', () => { it('should return the eth conversion rate', () => {
assert.deepEqual( assert.deepEqual(

@ -3,6 +3,7 @@ import sinon from 'sinon'
import proxyquire from 'proxyquire' import proxyquire from 'proxyquire'
import { import {
ONE_GWEI_IN_WEI_HEX, ONE_GWEI_IN_WEI_HEX,
SIMPLE_GAS_COST,
} from '../send.constants' } from '../send.constants'
const { const {
addCurrencies, addCurrencies,
@ -18,11 +19,19 @@ const stubs = {
addCurrencies: sinon.stub().callsFake((a, b, obj) => a + b), addCurrencies: sinon.stub().callsFake((a, b, obj) => a + b),
conversionUtil: sinon.stub().callsFake((val, obj) => parseInt(val, 16)), conversionUtil: sinon.stub().callsFake((val, obj) => parseInt(val, 16)),
conversionGTE: sinon.stub().callsFake((obj1, obj2) => obj1.value > obj2.value), conversionGTE: sinon.stub().callsFake((obj1, obj2) => obj1.value > obj2.value),
multiplyCurrencies: sinon.stub().callsFake((a, b) => a * b), multiplyCurrencies: sinon.stub().callsFake((a, b) => `${a}x${b}`),
calcTokenAmount: sinon.stub().callsFake((a, d) => 'calc:' + a + d), calcTokenAmount: sinon.stub().callsFake((a, d) => 'calc:' + a + d),
rawEncode: sinon.stub().returns([16, 1100]), rawEncode: sinon.stub().returns([16, 1100]),
} }
const EthQuery = function () {}
EthQuery.prototype.estimateGas = sinon.stub().callsFake(
(data) => Promise.resolve({ toString: (n) => `mockToString:${n}` })
)
EthQuery.prototype.getCode = sinon.stub().callsFake(
(address) => Promise.resolve(address.match(/isContract/) ? 'not-0x' : '0x')
)
const sendUtils = proxyquire('../send.utils.js', { const sendUtils = proxyquire('../send.utils.js', {
'../../conversion-util': { '../../conversion-util': {
addCurrencies: stubs.addCurrencies, addCurrencies: stubs.addCurrencies,
@ -34,6 +43,7 @@ const sendUtils = proxyquire('../send.utils.js', {
'ethereumjs-abi': { 'ethereumjs-abi': {
rawEncode: stubs.rawEncode, rawEncode: stubs.rawEncode,
}, },
'ethjs-query': EthQuery,
}) })
const { const {
@ -43,7 +53,6 @@ const {
estimateGasPriceFromRecentBlocks, estimateGasPriceFromRecentBlocks,
generateTokenTransferData, generateTokenTransferData,
getAmountErrorObject, getAmountErrorObject,
getParamsForGasEstimate,
calcTokenBalance, calcTokenBalance,
isBalanceSufficient, isBalanceSufficient,
isTokenBalanceSufficient, isTokenBalanceSufficient,
@ -54,7 +63,7 @@ describe('send utils', () => {
describe('calcGasTotal()', () => { describe('calcGasTotal()', () => {
it('should call multiplyCurrencies with the correct params and return the multiplyCurrencies return', () => { it('should call multiplyCurrencies with the correct params and return the multiplyCurrencies return', () => {
const result = calcGasTotal(12, 15) const result = calcGasTotal(12, 15)
assert.equal(result, 180) assert.equal(result, '12x15')
const call_ = stubs.multiplyCurrencies.getCall(0).args const call_ = stubs.multiplyCurrencies.getCall(0).args
assert.deepEqual( assert.deepEqual(
call_, call_,
@ -145,41 +154,6 @@ describe('send utils', () => {
}) })
}) })
describe('getParamsForGasEstimate()', () => {
it('should return from and gas properties if no symbol or data', () => {
assert.deepEqual(
getParamsForGasEstimate('mockAddress'),
{
from: 'mockAddress',
gas: '746a528800',
}
)
})
it('should return value property if selected token provided', () => {
assert.deepEqual(
getParamsForGasEstimate('mockAddress', { symbol: 'ABC' }),
{
from: 'mockAddress',
gas: '746a528800',
value: '0x0',
}
)
})
it('should return data property if data provided', () => {
assert.deepEqual(
getParamsForGasEstimate('mockAddress', { symbol: 'ABC' }, 'somedata'),
{
from: 'mockAddress',
gas: '746a528800',
value: '0x0',
data: 'somedata',
}
)
})
})
describe('calcTokenBalance()', () => { describe('calcTokenBalance()', () => {
it('should return the calculated token blance', () => { it('should return the calculated token blance', () => {
assert.equal(calcTokenBalance({ assert.equal(calcTokenBalance({
@ -271,38 +245,66 @@ describe('send utils', () => {
}) })
describe('estimateGas', () => { describe('estimateGas', () => {
let tempEthQuery const baseMockParams = {
beforeEach(() => { blockGasLimit: '0x64',
tempEthQuery = global.ethQuery selectedAddress: 'mockAddress',
global.ethQuery = { to: '0xisContract',
estimateGas: sinon.stub().callsFake((data, cb) => { }
return cb( const baseExpectedCall = {
data.isMockErr ? 'mockErr' : null, from: 'mockAddress',
Object.assign(data, { estimateGasCalled: true }) gas: '0x64x0.95',
to: '0xisContract',
}
afterEach(() => {
EthQuery.prototype.estimateGas.resetHistory()
EthQuery.prototype.getCode.resetHistory()
})
it('should call ethQuery.estimateGas with the expected params', async () => {
const result = await estimateGas(baseMockParams)
assert.equal(EthQuery.prototype.estimateGas.callCount, 1)
assert.deepEqual(
EthQuery.prototype.estimateGas.getCall(0).args[0],
baseExpectedCall
) )
assert.equal(result, 'mockToString:16')
}) })
}
it('should call ethQuery.estimateGas with a value of 0x0 if the passed selectedToken has a symbol', async () => {
const result = await estimateGas(Object.assign({ selectedToken: { symbol: true } }, baseMockParams))
assert.equal(EthQuery.prototype.estimateGas.callCount, 1)
assert.deepEqual(
EthQuery.prototype.estimateGas.getCall(0).args[0],
Object.assign({ value: '0x0' }, baseExpectedCall)
)
assert.equal(result, 'mockToString:16')
}) })
afterEach(() => { it('should call ethQuery.estimateGas with data if data is passed', async () => {
global.ethQuery = tempEthQuery const result = await estimateGas(Object.assign({ data: 'mockData' }, baseMockParams))
assert.equal(EthQuery.prototype.estimateGas.callCount, 1)
assert.deepEqual(
EthQuery.prototype.estimateGas.getCall(0).args[0],
Object.assign({ data: 'mockData' }, baseExpectedCall)
)
assert.equal(result, 'mockToString:16')
}) })
it('should call ethQuery.estimateGas and resolve that call\'s data', async () => { it('should call ethQuery.estimateGas with data if data is passed', async () => {
const result = await estimateGas({ mockParam: 'someData' }) const result = await estimateGas(Object.assign({ data: 'mockData' }, baseMockParams))
assert.equal(global.ethQuery.estimateGas.callCount, 1) assert.equal(EthQuery.prototype.estimateGas.callCount, 1)
assert.deepEqual( assert.deepEqual(
result, EthQuery.prototype.estimateGas.getCall(0).args[0],
{ mockParam: 'someData', estimateGasCalled: true } Object.assign({ data: 'mockData' }, baseExpectedCall)
) )
assert.equal(result, 'mockToString:16')
}) })
it('should reject with ethQuery.estimateGas error', async () => { it(`should return ${SIMPLE_GAS_COST} if ethQuery.getCode does not return '0x'`, async () => {
try { assert.equal(EthQuery.prototype.estimateGas.callCount, 0)
await estimateGas({ mockParam: 'someData', isMockErr: true }) const result = await estimateGas(Object.assign({}, baseMockParams, { to: '0x123' }))
} catch (err) { assert.equal(result, SIMPLE_GAS_COST)
assert.equal(err, 'mockErr')
}
}) })
}) })

@ -11,7 +11,8 @@
* @param {string} [options.fromNumericBase = 'hex' | 'dec' | 'BN'] The numeric basic of the passed value. * @param {string} [options.fromNumericBase = 'hex' | 'dec' | 'BN'] The numeric basic of the passed value.
* @param {string} [options.toNumericBase = 'hex' | 'dec' | 'BN'] The desired numeric basic of the result. * @param {string} [options.toNumericBase = 'hex' | 'dec' | 'BN'] The desired numeric basic of the result.
* @param {string} [options.fromDenomination = 'WEI'] The denomination of the passed value * @param {string} [options.fromDenomination = 'WEI'] The denomination of the passed value
* @param {number} [options.numberOfDecimals] The desired number of in the result * @param {string} [options.numberOfDecimals] The desired number of decimals in the result
* @param {string} [options.roundDown] The desired number of decimals to round down to
* @param {number} [options.conversionRate] The rate to use to make the fromCurrency -> toCurrency conversion * @param {number} [options.conversionRate] The rate to use to make the fromCurrency -> toCurrency conversion
* @returns {(number | string | BN)} * @returns {(number | string | BN)}
* *
@ -38,6 +39,7 @@ const BIG_NUMBER_GWEI_MULTIPLIER = new BigNumber('1000000000')
// Individual Setters // Individual Setters
const convert = R.invoker(1, 'times') const convert = R.invoker(1, 'times')
const round = R.invoker(2, 'round')(R.__, BigNumber.ROUND_HALF_DOWN) 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 invertConversionRate = conversionRate => () => new BigNumber(1.0).div(conversionRate)
const decToBigNumberViaString = n => R.pipe(String, toBigNumber['dec']) const decToBigNumberViaString = n => R.pipe(String, toBigNumber['dec'])
@ -104,6 +106,7 @@ const converter = R.pipe(
whenPredSetWithPropAndSetter(fromAndToCurrencyPropsNotEqual, 'conversionRate', convert), whenPredSetWithPropAndSetter(fromAndToCurrencyPropsNotEqual, 'conversionRate', convert),
whenPropApplySetterMap('toDenomination', toSpecifiedDenomination), whenPropApplySetterMap('toDenomination', toSpecifiedDenomination),
whenPredSetWithPropAndSetter(R.prop('numberOfDecimals'), 'numberOfDecimals', round), whenPredSetWithPropAndSetter(R.prop('numberOfDecimals'), 'numberOfDecimals', round),
whenPredSetWithPropAndSetter(R.prop('roundDown'), 'roundDown', roundDown),
whenPropApplySetterMap('toNumericBase', baseChange), whenPropApplySetterMap('toNumericBase', baseChange),
R.view(R.lensProp('value')) R.view(R.lensProp('value'))
) )

Loading…
Cancel
Save