From b521058274f3788ea695b9c3cd78b73ff5331c0a Mon Sep 17 00:00:00 2001 From: Pierre Bertet Date: Thu, 25 Jun 2020 09:59:38 +0100 Subject: [PATCH 1/5] Add Jest --- apps/finance/app/.babelrc | 21 ++++++++++++++++----- apps/finance/app/package.json | 6 +++++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/apps/finance/app/.babelrc b/apps/finance/app/.babelrc index 7adcae8d5f..7d24d1da6a 100644 --- a/apps/finance/app/.babelrc +++ b/apps/finance/app/.babelrc @@ -5,13 +5,24 @@ { "modules": false, "useBuiltIns": "entry", - "core-js": 3, - "shippedProposals": true, + "corejs": 3, + "shippedProposals": true } ], "@babel/preset-react" ], - "plugins": [ - ["styled-components", { "displayName": true }], - ] + "plugins": [["styled-components", { "displayName": true }]], + "env": { + "test": { + "presets": [ + [ + "@babel/preset-env", + { + "modules": "commonjs", + "targets": { "node": "current" } + } + ] + ] + } + } } diff --git a/apps/finance/app/package.json b/apps/finance/app/package.json index 76fcf3d5fb..7a52d6b8f3 100644 --- a/apps/finance/app/package.json +++ b/apps/finance/app/package.json @@ -27,17 +27,20 @@ "@babel/preset-env": "^7.10.2", "@babel/preset-react": "^7.10.1", "babel-eslint": "^10.0.1", + "babel-jest": "^26.1.0", "babel-plugin-styled-components": "^1.10.7", "eslint": "^5.6.0", "eslint-config-prettier": "^3.1.0", "eslint-config-standard": "^12.0.0", "eslint-config-standard-react": "^7.0.2", "eslint-plugin-import": "^2.8.0", + "eslint-plugin-jest": "^23.17.1", "eslint-plugin-node": "^7.0.1", "eslint-plugin-prettier": "^2.7.0", "eslint-plugin-promise": "^4.0.1", "eslint-plugin-react": "^7.5.1", "eslint-plugin-standard": "^4.0.0", + "jest": "^26.1.0", "parcel-bundler": "^1.12.4", "parcel-plugin-bundle-visualiser": "^1.2.0", "prettier": "^1.11.1" @@ -49,7 +52,8 @@ "build:script": "parcel build src/script.js --out-dir build/", "watch:script": "parcel watch src/script.js --out-dir build/ --no-hmr", "sync-assets": "copy-aragon-ui-assets -n aragon-ui ./build && rsync -rtu ./public/ ./build", - "now-build": "npm run build" + "now-build": "npm run build", + "test": "jest" }, "browserslist": [ ">2%", From c2c9a2637adc66c38c5bbf32f5d719930f2fa9c0 Mon Sep 17 00:00:00 2001 From: Pierre Bertet Date: Thu, 25 Jun 2020 10:00:41 +0100 Subject: [PATCH 2/5] Move to convertAmount() --- .../app/src/components/BalanceToken.js | 12 +--- apps/finance/app/src/components/Balances.js | 13 ++-- apps/finance/app/src/lib/conversion-utils.js | 62 +++---------------- .../app/src/lib/conversion-utils.test.js | 16 +++++ 4 files changed, 36 insertions(+), 67 deletions(-) create mode 100644 apps/finance/app/src/lib/conversion-utils.test.js diff --git a/apps/finance/app/src/components/BalanceToken.js b/apps/finance/app/src/components/BalanceToken.js index 06e4088e6a..e6d8b1a561 100644 --- a/apps/finance/app/src/components/BalanceToken.js +++ b/apps/finance/app/src/components/BalanceToken.js @@ -8,8 +8,8 @@ import { tokenIconUrl } from '../lib/icon-utils' function BalanceToken({ address, amount, + amountConverted, compact, - convertedAmount, decimals, symbol, verified, @@ -82,24 +82,18 @@ function BalanceToken({ ${textStyle('body2')} `} > - {convertedAmount.isNeg() - ? '−' - : `$${formatTokenAmount(convertedAmount, decimals)}`} + {amountConverted ? `$${amountConverted}` : '−'} ) } -BalanceToken.defaultProps = { - convertedAmount: new BN(-1), -} - BalanceToken.propTypes = { address: PropTypes.string.isRequired, amount: PropTypes.instanceOf(BN).isRequired, + amountConverted: PropTypes.string, compact: PropTypes.bool.isRequired, - convertedAmount: PropTypes.instanceOf(BN), decimals: PropTypes.instanceOf(BN).isRequired, symbol: PropTypes.string.isRequired, verified: PropTypes.bool.isRequired, diff --git a/apps/finance/app/src/components/Balances.js b/apps/finance/app/src/components/Balances.js index b3e0ba9dc7..c2778930b3 100644 --- a/apps/finance/app/src/components/Balances.js +++ b/apps/finance/app/src/components/Balances.js @@ -2,7 +2,7 @@ import React, { useMemo } from 'react' import BN from 'bn.js' import { Box, GU, textStyle, useTheme, useLayout } from '@aragon/ui' import BalanceToken from './BalanceToken' -import { getConvertedAmount, useConvertRates } from '../lib/conversion-utils' +import { convertAmount, useConvertRates } from '../lib/conversion-utils' // Prepare the balances for the BalanceToken component function useBalanceItems(balances) { @@ -18,9 +18,10 @@ function useBalanceItems(balances) { return { address, amount, - convertedAmount: convertRates[symbol] - ? getConvertedAmount(amount, convertRates[symbol], decimals) - : new BN('-1'), + amountConverted: + amount && decimals && convertRates[symbol] + ? convertAmount(amount, decimals, 1 / convertRates[symbol]) + : '', decimals, symbol, verified, @@ -84,7 +85,7 @@ function Balances({ balances }) { ({ address, amount, - convertedAmount, + amountConverted, decimals, symbol, verified, @@ -107,7 +108,7 @@ function Balances({ balances }) { address={address} amount={amount} compact={compact} - convertedAmount={convertedAmount} + amountConverted={amountConverted} decimals={decimals} symbol={symbol} verified={verified} diff --git a/apps/finance/app/src/lib/conversion-utils.js b/apps/finance/app/src/lib/conversion-utils.js index 3aea0a4b65..43a3803e13 100644 --- a/apps/finance/app/src/lib/conversion-utils.js +++ b/apps/finance/app/src/lib/conversion-utils.js @@ -1,66 +1,24 @@ import { useEffect, useRef, useState } from 'react' import BN from 'bn.js' +import { formatTokenAmount } from '@aragon/ui' const CONVERT_API_RETRY_DELAY = 2 * 1000 const CONVERT_API_RETRY_DELAY_MAX = 60 * 1000 - -const USD_DECIMALS = new BN('2') +const CONVERT_PRECISION = 9 function convertRatesUrl(symbolsQuery) { return `https://min-api.cryptocompare.com/data/price?fsym=USD&tsyms=${symbolsQuery}` } -function formatConvertRate(convertRate, decimals) { - const [whole = '', dec = ''] = convertRate.split('.') - const parsedWhole = whole.replace(/^0*/, '') - const parsedDec = dec.replace(/0*$/, '') - // parsedWhole could be empty, - // so in this case, we wanna remove leading zeros. - const fullyParsedDec = parsedWhole ? parsedDec : parsedDec.replace(/^0*/, '') - - // Even if we remove leading zeroes from the decimal - // part, we want to count as if we "shifted" them - const decimalsToShift = decimals.sub(new BN(parsedDec.length.toString())) - // Apart from always considering the USD decimals (2), - // if there's the strange case that the above is negative, - // we take it as a carry as we know we already shifted to far, - // and will compensate by shifting the token amount by this much - const carryAmount = - decimalsToShift.toNumber() < 0 - ? decimalsToShift.add(USD_DECIMALS) - : USD_DECIMALS - // The remaining total amount to shift through bn.js to avoid overflow. - const amountToShift = new BN('10').pow( - decimalsToShift.toNumber() > 0 ? decimalsToShift : new BN('0') - ) - - // Finish shifting the whole number through BN.js to avoid overflow, - return [ - new BN(`${parsedWhole}${fullyParsedDec}`).mul(amountToShift), - carryAmount, - ] -} - -export function getConvertedAmount(amount, convertRate, decimals) { - const [formattedConvertRate, carryAmount] = formatConvertRate( - convertRate.toString(), - decimals +// Convert an amount into another one using a rate (Number). +export function convertAmount(amount, decimals, rate, options) { + return formatTokenAmount( + new BN(amount) + .mul(new BN(10).pow(new BN(CONVERT_PRECISION))) + .mul(new BN(rate * 10 ** CONVERT_PRECISION)), + new BN(decimals).add(new BN(CONVERT_PRECISION * 2)), + options ) - - // Get the actual precision we need to re-add when calculations are over - const precisionTarget = new BN('10').pow(decimals.sub(USD_DECIMALS)) - const convertedAmount = amount - // Shift the amount to take into account the USD decimals - // + any leftover - .mul(new BN('10').pow(carryAmount)) - // Actually convert to an USD rate - .div(formattedConvertRate) - // Return it to its original precision - // Note that we don't have to subtract the "extra carry" - // as it's undone during the division - .mul(precisionTarget) - - return convertedAmount } export function useConvertRates(symbols) { diff --git a/apps/finance/app/src/lib/conversion-utils.test.js b/apps/finance/app/src/lib/conversion-utils.test.js new file mode 100644 index 0000000000..0fd74e3359 --- /dev/null +++ b/apps/finance/app/src/lib/conversion-utils.test.js @@ -0,0 +1,16 @@ +import BN from 'bn.js' +import { convertAmount } from './conversion-utils' + +describe('convertAmount()', () => { + test('Should convert and format amounts', () => { + expect( + String(convertAmount('10663060000000000000000', 18, 0.995, { digits: 2 })) + ).toBe('10,609.74') + expect( + String(convertAmount('10663060000000000000000', 18, 0.995, { digits: 3 })) + ).toBe('10,609.745') + expect( + String(convertAmount('10663060000000000000000', 18, 0.995, { digits: 4 })) + ).toBe('10,609.7447') + }) +}) From e07cbd8c54ee606606c8c7cabb6e29723ae7ac18 Mon Sep 17 00:00:00 2001 From: Pierre Bertet Date: Thu, 25 Jun 2020 10:18:51 +0100 Subject: [PATCH 3/5] Add comment --- apps/finance/app/src/lib/conversion-utils.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/finance/app/src/lib/conversion-utils.js b/apps/finance/app/src/lib/conversion-utils.js index 43a3803e13..b809a051c8 100644 --- a/apps/finance/app/src/lib/conversion-utils.js +++ b/apps/finance/app/src/lib/conversion-utils.js @@ -10,7 +10,15 @@ function convertRatesUrl(symbolsQuery) { return `https://min-api.cryptocompare.com/data/price?fsym=USD&tsyms=${symbolsQuery}` } -// Convert an amount into another one using a rate (Number). +/** + * Convert an amount into another one using a rate. + * + * @param {BigInt|string|number} amount amount to convert + * @param {BigInt|string|number} decimals number of decimals for the amount + * @param {string|number} rate the rate to use for the conversion + * @param {Object} [options] options passed to formatTokenAmount() + * @returns {string} the formatted amount converted + */ export function convertAmount(amount, decimals, rate, options) { return formatTokenAmount( new BN(amount) From de76a63408d897ee74c24e592904bcb3e688b69f Mon Sep 17 00:00:00 2001 From: Pierre Bertet Date: Thu, 25 Jun 2020 10:20:05 +0100 Subject: [PATCH 4/5] BigInt => BN conversions --- apps/finance/app/src/lib/conversion-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/finance/app/src/lib/conversion-utils.js b/apps/finance/app/src/lib/conversion-utils.js index b809a051c8..b7d64477fb 100644 --- a/apps/finance/app/src/lib/conversion-utils.js +++ b/apps/finance/app/src/lib/conversion-utils.js @@ -21,7 +21,7 @@ function convertRatesUrl(symbolsQuery) { */ export function convertAmount(amount, decimals, rate, options) { return formatTokenAmount( - new BN(amount) + new BN(String(amount)) .mul(new BN(10).pow(new BN(CONVERT_PRECISION))) .mul(new BN(rate * 10 ** CONVERT_PRECISION)), new BN(decimals).add(new BN(CONVERT_PRECISION * 2)), From af337d23befacc2403e7fccb627d7e461202b08b Mon Sep 17 00:00:00 2001 From: Pierre Bertet Date: Thu, 25 Jun 2020 10:24:10 +0100 Subject: [PATCH 5/5] Type conversion --- apps/finance/app/src/lib/conversion-utils.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/finance/app/src/lib/conversion-utils.js b/apps/finance/app/src/lib/conversion-utils.js index b7d64477fb..d4ce84e1de 100644 --- a/apps/finance/app/src/lib/conversion-utils.js +++ b/apps/finance/app/src/lib/conversion-utils.js @@ -20,11 +20,13 @@ function convertRatesUrl(symbolsQuery) { * @returns {string} the formatted amount converted */ export function convertAmount(amount, decimals, rate, options) { + amount = new BN(String(amount)) + decimals = parseInt(String(decimals), 10) return formatTokenAmount( - new BN(String(amount)) + amount .mul(new BN(10).pow(new BN(CONVERT_PRECISION))) .mul(new BN(rate * 10 ** CONVERT_PRECISION)), - new BN(decimals).add(new BN(CONVERT_PRECISION * 2)), + decimals + CONVERT_PRECISION * 2, options ) }