diff --git a/web/cashtab/src/components/Send/Send.js b/web/cashtab/src/components/Send/Send.js --- a/web/cashtab/src/components/Send/Send.js +++ b/web/cashtab/src/components/Send/Send.js @@ -22,7 +22,7 @@ toLegacy, } from '@components/Common/Ticker.js'; import { Event } from '@utils/GoogleAnalytics'; -import { shouldRejectAmountInput } from '@utils/validation'; +import { fiatToCrypto, shouldRejectAmountInput } from '@utils/validation'; export const BalanceHeader = styled.div` p { color: #777; @@ -209,7 +209,7 @@ let bchValue = value; if (selectedCurrency === 'USD') { - bchValue = (value / fiatPrice).toFixed(8); + bchValue = fiatToCrypto(value, fiatPrice); } try { @@ -379,9 +379,9 @@ 2, )} USD`; } else { - fiatPriceString = `${(Number(formData.value) / fiatPrice).toFixed( - 8, - )} ${currency.ticker}`; + fiatPriceString = `${ + formData.value ? fiatToCrypto(formData.value, fiatPrice) : '0' + } ${currency.ticker}`; } } diff --git a/web/cashtab/src/utils/__tests__/validation.test.js b/web/cashtab/src/utils/__tests__/validation.test.js --- a/web/cashtab/src/utils/__tests__/validation.test.js +++ b/web/cashtab/src/utils/__tests__/validation.test.js @@ -1,4 +1,4 @@ -import { shouldRejectAmountInput } from '../validation'; +import { shouldRejectAmountInput, fiatToCrypto } from '../validation'; import { currency } from '@components/Common/Ticker.js'; describe('Validation utils', () => { @@ -71,4 +71,12 @@ shouldRejectAmountInput('17.123456789', currency.ticker, 20.0, 35), ).toBe(expectedValidationError); }); + it(`Returns expected crypto amount with 8 decimals of precision even if inputs have higher precision`, () => { + expect(fiatToCrypto('10.97231694823432', 20.3231342349234234)).toBe( + '0.53989295', + ); + }); + it(`Returns expected crypto amount with 8 decimals of precision even if inputs have lower precision`, () => { + expect(fiatToCrypto('10.94', 10)).toBe('1.09400000'); + }); }); diff --git a/web/cashtab/src/utils/validation.js b/web/cashtab/src/utils/validation.js --- a/web/cashtab/src/utils/validation.js +++ b/web/cashtab/src/utils/validation.js @@ -1,3 +1,4 @@ +import BigNumber from 'bignumber.js'; import { currency } from '@components/Common/Ticker.js'; // Validate cash amount @@ -9,20 +10,21 @@ ) => { // Take cashAmount as input, a string from form input let error = false; - let testedAmount = cashAmount; + let testedAmount = new BigNumber(cashAmount); if (selectedCurrency === 'USD') { - testedAmount = (cashAmount / fiatPrice).toFixed(8); + // Ensure no more than 8 decimal places + testedAmount = new BigNumber(fiatToCrypto(cashAmount, fiatPrice)); } // Validate value for > 0 if (isNaN(testedAmount)) { error = 'Amount must be a number'; - } else if (testedAmount <= 0) { + } else if (testedAmount.lte(0)) { error = 'Amount must be greater than 0'; - } else if (testedAmount < currency.dust) { + } else if (testedAmount.lt(currency.dust)) { error = `Send amount must be at least ${currency.dust} ${currency.ticker}`; - } else if (testedAmount > totalCashBalance) { + } else if (testedAmount.gt(totalCashBalance)) { error = `Amount cannot exceed your ${currency.ticker} balance`; } else if (!isNaN(testedAmount) && testedAmount.toString().includes('.')) { if (testedAmount.toString().split('.')[1].length > 8) { @@ -32,3 +34,11 @@ // return false if no error, or string error msg if error return error; }; + +export const fiatToCrypto = (fiatAmount, fiatPrice) => { + // Return a string with no more than 8 decimal places + let cryptoAmount = new BigNumber(fiatAmount) + .div(new BigNumber(fiatPrice)) + .toFixed(8); + return cryptoAmount; +};