1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Fix BigNumber issues (#9860)

* Document where we need BigNumber-related changes

* Fix 1 unit test

* Debug progress

* Add required values for each upstream usage of getBigNumber

* Switch to base 10

* Address feedback
This commit is contained in:
David Walsh 2020-11-13 00:08:18 -06:00 committed by GitHub
parent ed27c359c6
commit 67303b7865
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 56 additions and 9 deletions

View File

@ -80,6 +80,8 @@ export default class TokenInput extends PureComponent {
const multiplier = Math.pow(10, Number(decimals || 0)) const multiplier = Math.pow(10, Number(decimals || 0))
const hexValue = multiplyCurrencies(decimalValue || 0, multiplier, { const hexValue = multiplyCurrencies(decimalValue || 0, multiplier, {
multiplicandBase: 10,
multiplierBase: 10,
toNumericBase: 'hex', toNumericBase: 'hex',
}) })

View File

@ -39,19 +39,23 @@ export function getHexGasTotal({ gasLimit, gasPrice }) {
} }
export function addEth(...args) { export function addEth(...args) {
return args.reduce((acc, base) => { return args.reduce((acc, ethAmount) => {
return addCurrencies(acc, base, { return addCurrencies(acc, ethAmount, {
toNumericBase: 'dec', toNumericBase: 'dec',
numberOfDecimals: 6, numberOfDecimals: 6,
aBase: 10,
bBase: 10,
}) })
}) })
} }
export function addFiat(...args) { export function addFiat(...args) {
return args.reduce((acc, base) => { return args.reduce((acc, fiatAmount) => {
return addCurrencies(acc, base, { return addCurrencies(acc, fiatAmount, {
toNumericBase: 'dec', toNumericBase: 'dec',
numberOfDecimals: 2, numberOfDecimals: 2,
aBase: 10,
bBase: 10,
}) })
}) })
} }

View File

@ -54,6 +54,11 @@ const baseChange = {
BN: (n) => new BN(n.toString(16)), BN: (n) => new BN(n.toString(16)),
} }
// Utility function for checking base types
const isValidBase = (base) => {
return Number.isInteger(base) && base > 1
}
/** /**
* Defines the base type of numeric value * Defines the base type of numeric value
* @typedef {('hex' | 'dec' | 'BN')} NumericBase * @typedef {('hex' | 'dec' | 'BN')} NumericBase
@ -162,6 +167,10 @@ const conversionUtil = (
}) })
const getBigNumber = (value, base) => { const getBigNumber = (value, base) => {
if (!isValidBase(base)) {
throw new Error('Must specificy valid base')
}
// We don't include 'number' here, because BigNumber will throw if passed // We don't include 'number' here, because BigNumber will throw if passed
// a number primitive it considers unsafe. // a number primitive it considers unsafe.
if (typeof value === 'string' || value instanceof BigNumber) { if (typeof value === 'string' || value instanceof BigNumber) {
@ -173,6 +182,11 @@ const getBigNumber = (value, base) => {
const addCurrencies = (a, b, options = {}) => { const addCurrencies = (a, b, options = {}) => {
const { aBase, bBase, ...conversionOptions } = options const { aBase, bBase, ...conversionOptions } = options
if (!isValidBase(aBase) || !isValidBase(bBase)) {
throw new Error('Must specify valid aBase and bBase')
}
const value = getBigNumber(a, aBase).add(getBigNumber(b, bBase)) const value = getBigNumber(a, aBase).add(getBigNumber(b, bBase))
return converter({ return converter({
@ -183,6 +197,11 @@ const addCurrencies = (a, b, options = {}) => {
const subtractCurrencies = (a, b, options = {}) => { const subtractCurrencies = (a, b, options = {}) => {
const { aBase, bBase, ...conversionOptions } = options const { aBase, bBase, ...conversionOptions } = options
if (!isValidBase(aBase) || !isValidBase(bBase)) {
throw new Error('Must specify valid aBase and bBase')
}
const value = getBigNumber(a, aBase).minus(getBigNumber(b, bBase)) const value = getBigNumber(a, aBase).minus(getBigNumber(b, bBase))
return converter({ return converter({
@ -194,6 +213,10 @@ const subtractCurrencies = (a, b, options = {}) => {
const multiplyCurrencies = (a, b, options = {}) => { const multiplyCurrencies = (a, b, options = {}) => {
const { multiplicandBase, multiplierBase, ...conversionOptions } = options const { multiplicandBase, multiplierBase, ...conversionOptions } = options
if (!isValidBase(multiplicandBase) || !isValidBase(multiplierBase)) {
throw new Error('Must specify valid multiplicandBase and multiplierBase')
}
const value = getBigNumber(a, multiplicandBase).times( const value = getBigNumber(a, multiplicandBase).times(
getBigNumber(b, multiplierBase), getBigNumber(b, multiplierBase),
) )

View File

@ -5,17 +5,26 @@ import { addCurrencies, conversionUtil } from './conversion-util'
describe('conversion utils', function () { describe('conversion utils', function () {
describe('addCurrencies()', function () { describe('addCurrencies()', function () {
it('add whole numbers', function () { it('add whole numbers', function () {
const result = addCurrencies(3, 9) const result = addCurrencies(3, 9, {
aBase: 10,
bBase: 10,
})
assert.equal(result.toNumber(), 12) assert.equal(result.toNumber(), 12)
}) })
it('add decimals', function () { it('add decimals', function () {
const result = addCurrencies(1.3, 1.9) const result = addCurrencies(1.3, 1.9, {
aBase: 10,
bBase: 10,
})
assert.equal(result.toNumber(), 3.2) assert.equal(result.toNumber(), 3.2)
}) })
it('add repeating decimals', function () { it('add repeating decimals', function () {
const result = addCurrencies(1 / 3, 1 / 9) const result = addCurrencies(1 / 3, 1 / 9, {
aBase: 10,
bBase: 10,
})
assert.equal(result.toNumber(), 0.4444444444444444) assert.equal(result.toNumber(), 0.4444444444444444)
}) })
}) })

View File

@ -217,6 +217,10 @@ export function getTokenFiatAmount(
const currentTokenToFiatRate = multiplyCurrencies( const currentTokenToFiatRate = multiplyCurrencies(
contractExchangeRate, contractExchangeRate,
conversionRate, conversionRate,
{
multiplicandBase: 10,
multiplierBase: 10,
},
) )
const currentTokenInFiat = conversionUtil(tokenAmount, { const currentTokenInFiat = conversionUtil(tokenAmount, {
fromNumericBase: 'dec', fromNumericBase: 'dec',

View File

@ -152,9 +152,11 @@ export async function isSmartContractAddress(address) {
} }
export function sumHexes(...args) { export function sumHexes(...args) {
const total = args.reduce((acc, base) => { const total = args.reduce((acc, hexAmount) => {
return addCurrencies(acc, base, { return addCurrencies(acc, hexAmount, {
toNumericBase: 'hex', toNumericBase: 'hex',
aBase: 16,
bBase: 16,
}) })
}) })

View File

@ -12,8 +12,11 @@ export function calcMaxAmount({ balance, gasTotal, sendToken, tokenBalance }) {
? multiplyCurrencies(tokenBalance, multiplier, { ? multiplyCurrencies(tokenBalance, multiplier, {
toNumericBase: 'hex', toNumericBase: 'hex',
multiplicandBase: 16, multiplicandBase: 16,
multiplierBase: 10,
}) })
: subtractCurrencies(addHexPrefix(balance), addHexPrefix(gasTotal), { : subtractCurrencies(addHexPrefix(balance), addHexPrefix(gasTotal), {
toNumericBase: 'hex', toNumericBase: 'hex',
aBase: 16,
bBase: 16,
}) })
} }