REF: Currency module to TS (#6052)

This commit is contained in:
Marcos Rodriguez Vélez 2024-01-28 11:11:08 -04:00 committed by GitHub
parent e4adb0f742
commit bec42fe42d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 392 additions and 402 deletions

4
App.js
View file

@ -33,8 +33,8 @@ import HandoffComponent from './components/handoff';
import Privacy from './blue_modules/Privacy'; import Privacy from './blue_modules/Privacy';
import triggerHapticFeedback, { HapticFeedbackTypes } from './blue_modules/hapticFeedback'; import triggerHapticFeedback, { HapticFeedbackTypes } from './blue_modules/hapticFeedback';
import MenuElements from './components/MenuElements'; import MenuElements from './components/MenuElements';
import { updateExchangeRate } from './blue_modules/currency';
const A = require('./blue_modules/analytics'); const A = require('./blue_modules/analytics');
const currency = require('./blue_modules/currency');
const eventEmitter = Platform.OS === 'ios' ? new NativeEventEmitter(NativeModules.EventEmitter) : undefined; const eventEmitter = Platform.OS === 'ios' ? new NativeEventEmitter(NativeModules.EventEmitter) : undefined;
const { EventEmitter, SplashScreen } = NativeModules; const { EventEmitter, SplashScreen } = NativeModules;
@ -203,7 +203,7 @@ const App = () => {
if (wallets.length === 0) return; if (wallets.length === 0) return;
if ((appState.current.match(/background/) && nextAppState === 'active') || nextAppState === undefined) { if ((appState.current.match(/background/) && nextAppState === 'active') || nextAppState === undefined) {
setTimeout(() => A(A.ENUM.APP_UNSUSPENDED), 2000); setTimeout(() => A(A.ENUM.APP_UNSUSPENDED), 2000);
currency.updateExchangeRate(); updateExchangeRate();
const processed = await processPushNotifications(); const processed = await processPushNotifications();
if (processed) return; if (processed) return;
const clipboard = await BlueClipboard().getClipboardContent(); const clipboard = await BlueClipboard().getClipboardContent();

View file

@ -25,6 +25,7 @@ import {
} from './class/'; } from './class/';
import { randomBytes } from './class/rng'; import { randomBytes } from './class/rng';
import alert from './components/Alert'; import alert from './components/Alert';
import { initCurrencyDaemon } from './blue_modules/currency';
const encryption = require('./blue_modules/encryption'); const encryption = require('./blue_modules/encryption');
const Realm = require('realm'); const Realm = require('realm');
@ -32,7 +33,6 @@ const createHash = require('create-hash');
let usedBucketNum = false; let usedBucketNum = false;
let savingInProgress = 0; // its both a flag and a counter of attempts to write to disk let savingInProgress = 0; // its both a flag and a counter of attempts to write to disk
const prompt = require('./helpers/prompt'); const prompt = require('./helpers/prompt');
const currency = require('./blue_modules/currency');
const BlueElectrum = require('./blue_modules/BlueElectrum'); const BlueElectrum = require('./blue_modules/BlueElectrum');
BlueElectrum.connectMain(); BlueElectrum.connectMain();
@ -939,6 +939,6 @@ const startAndDecrypt = async retry => {
BlueApp.startAndDecrypt = startAndDecrypt; BlueApp.startAndDecrypt = startAndDecrypt;
BlueApp.AppStorage = AppStorage; BlueApp.AppStorage = AppStorage;
currency.init(); initCurrencyDaemon();
module.exports = BlueApp; module.exports = BlueApp;

View file

@ -1,261 +0,0 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import DefaultPreference from 'react-native-default-preference';
import * as RNLocalize from 'react-native-localize';
import BigNumber from 'bignumber.js';
import { FiatUnit, getFiatRate } from '../models/fiatUnit';
import WidgetCommunication from './WidgetCommunication';
const PREFERRED_CURRENCY_STORAGE_KEY = 'preferredCurrency';
const EXCHANGE_RATES_STORAGE_KEY = 'currency';
let preferredFiatCurrency = FiatUnit.USD;
let exchangeRates = { LAST_UPDATED_ERROR: false };
let lastTimeUpdateExchangeRateWasCalled = 0;
let skipUpdateExchangeRate = false;
const LAST_UPDATED = 'LAST_UPDATED';
/**
* Saves to storage preferred currency, whole object
* from `./models/fiatUnit`
*
* @param item {Object} one of the values in `./models/fiatUnit`
* @returns {Promise<void>}
*/
async function setPrefferedCurrency(item) {
await AsyncStorage.setItem(PREFERRED_CURRENCY_STORAGE_KEY, JSON.stringify(item));
await DefaultPreference.setName('group.io.bluewallet.bluewallet');
await DefaultPreference.set('preferredCurrency', item.endPointKey);
await DefaultPreference.set('preferredCurrencyLocale', item.locale.replace('-', '_'));
WidgetCommunication.reloadAllTimelines();
}
async function getPreferredCurrency() {
const preferredCurrency = await JSON.parse(await AsyncStorage.getItem(PREFERRED_CURRENCY_STORAGE_KEY));
await DefaultPreference.setName('group.io.bluewallet.bluewallet');
await DefaultPreference.set('preferredCurrency', preferredCurrency.endPointKey);
await DefaultPreference.set('preferredCurrencyLocale', preferredCurrency.locale.replace('-', '_'));
return preferredCurrency;
}
async function _restoreSavedExchangeRatesFromStorage() {
try {
exchangeRates = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
if (!exchangeRates) exchangeRates = { LAST_UPDATED_ERROR: false };
} catch (_) {
exchangeRates = { LAST_UPDATED_ERROR: false };
}
}
async function _restoreSavedPreferredFiatCurrencyFromStorage() {
try {
preferredFiatCurrency = JSON.parse(await AsyncStorage.getItem(PREFERRED_CURRENCY_STORAGE_KEY));
if (preferredFiatCurrency === null) {
throw Error('No Preferred Fiat selected');
}
preferredFiatCurrency = FiatUnit[preferredFiatCurrency.endPointKey] || preferredFiatCurrency;
// ^^^ in case configuration in json file changed (and is different from what we stored) we reload it
} catch (_) {
const deviceCurrencies = RNLocalize.getCurrencies();
if (Object.keys(FiatUnit).some(unit => unit === deviceCurrencies[0])) {
preferredFiatCurrency = FiatUnit[deviceCurrencies[0]];
} else {
preferredFiatCurrency = FiatUnit.USD;
}
}
}
/**
* actual function to reach api and get fresh currency exchange rate. checks LAST_UPDATED time and skips entirely
* if called too soon (30min); saves exchange rate (with LAST_UPDATED info) to storage.
* should be called when app thinks its a good time to refresh exchange rate
*
* @return {Promise<void>}
*/
async function updateExchangeRate() {
if (skipUpdateExchangeRate) return;
if (+new Date() - lastTimeUpdateExchangeRateWasCalled <= 10 * 1000) {
// simple debounce so theres no race conditions
return;
}
lastTimeUpdateExchangeRateWasCalled = +new Date();
if (+new Date() - exchangeRates[LAST_UPDATED] <= 30 * 60 * 1000) {
// not updating too often
return;
}
console.log('updating exchange rate...');
let rate;
try {
rate = await getFiatRate(preferredFiatCurrency.endPointKey);
exchangeRates[LAST_UPDATED] = +new Date();
exchangeRates['BTC_' + preferredFiatCurrency.endPointKey] = rate;
exchangeRates.LAST_UPDATED_ERROR = false;
await AsyncStorage.setItem(EXCHANGE_RATES_STORAGE_KEY, JSON.stringify(exchangeRates));
} catch (Err) {
console.log('Error encountered when attempting to update exchange rate...');
console.warn(Err.message);
rate = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
rate = rate || {}; // init if its null
rate.LAST_UPDATED_ERROR = true;
exchangeRates.LAST_UPDATED_ERROR = true;
await AsyncStorage.setItem(EXCHANGE_RATES_STORAGE_KEY, JSON.stringify(rate));
throw Err;
}
}
async function isRateOutdated() {
try {
const rate = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
return rate.LAST_UPDATED_ERROR || +new Date() - rate.LAST_UPDATED >= 31 * 60 * 1000;
} catch {
return true;
}
}
/**
* this function reads storage and restores current preferred fiat currency & last saved exchange rate, then calls
* updateExchangeRate() to update rates.
* should be called when the app starts and when user changes preferred fiat (with TRUE argument so underlying
* `updateExchangeRate()` would actually update rates via api).
*
* @param clearLastUpdatedTime {boolean} set to TRUE for the underlying
*
* @return {Promise<void>}
*/
async function init(clearLastUpdatedTime = false) {
await _restoreSavedExchangeRatesFromStorage();
await _restoreSavedPreferredFiatCurrencyFromStorage();
if (clearLastUpdatedTime) {
exchangeRates[LAST_UPDATED] = 0;
lastTimeUpdateExchangeRateWasCalled = 0;
}
return updateExchangeRate();
}
function satoshiToLocalCurrency(satoshi, format = true) {
if (!exchangeRates['BTC_' + preferredFiatCurrency.endPointKey]) {
updateExchangeRate();
return '...';
}
let b = new BigNumber(satoshi).dividedBy(100000000).multipliedBy(exchangeRates['BTC_' + preferredFiatCurrency.endPointKey]);
if (b.isGreaterThanOrEqualTo(0.005) || b.isLessThanOrEqualTo(-0.005)) {
b = b.toFixed(2);
} else {
b = b.toPrecision(2);
}
if (format === false) return b;
let formatter;
try {
formatter = new Intl.NumberFormat(preferredFiatCurrency.locale, {
style: 'currency',
currency: preferredFiatCurrency.endPointKey,
minimumFractionDigits: 2,
maximumFractionDigits: 8,
});
} catch (error) {
console.warn(error);
console.log(error);
formatter = new Intl.NumberFormat(FiatUnit.USD.locale, {
style: 'currency',
currency: preferredFiatCurrency.endPointKey,
minimumFractionDigits: 2,
maximumFractionDigits: 8,
});
}
return formatter.format(b);
}
function BTCToLocalCurrency(bitcoin) {
let sat = new BigNumber(bitcoin);
sat = sat.multipliedBy(100000000).toNumber();
return satoshiToLocalCurrency(sat);
}
async function mostRecentFetchedRate() {
const currencyInformation = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
const formatter = new Intl.NumberFormat(preferredFiatCurrency.locale, {
style: 'currency',
currency: preferredFiatCurrency.endPointKey,
});
return {
LastUpdated: currencyInformation[LAST_UPDATED],
Rate: formatter.format(currencyInformation[`BTC_${preferredFiatCurrency.endPointKey}`]),
};
}
function satoshiToBTC(satoshi) {
let b = new BigNumber(satoshi);
b = b.dividedBy(100000000);
return b.toString(10);
}
function btcToSatoshi(btc) {
return new BigNumber(btc).multipliedBy(100000000).toNumber();
}
function fiatToBTC(fiatFloat) {
let b = new BigNumber(fiatFloat);
b = b.dividedBy(exchangeRates['BTC_' + preferredFiatCurrency.endPointKey]).toFixed(8);
return b;
}
function getCurrencySymbol() {
return preferredFiatCurrency.symbol;
}
/**
* Used to mock data in tests
*
* @param {object} currency, one of FiatUnit.*
*/
function _setPreferredFiatCurrency(currency) {
preferredFiatCurrency = currency;
}
/**
* Used to mock data in tests
*
* @param {string} pair as expected by rest of this module, e.g 'BTC_JPY' or 'BTC_USD'
* @param {number} rate exchange rate
*/
function _setExchangeRate(pair, rate) {
exchangeRates[pair] = rate;
}
/**
* Used in unit tests, so the `currency` module wont launch actual http request
*/
function _setSkipUpdateExchangeRate() {
skipUpdateExchangeRate = true;
}
module.exports.updateExchangeRate = updateExchangeRate;
module.exports.init = init;
module.exports.satoshiToLocalCurrency = satoshiToLocalCurrency;
module.exports.fiatToBTC = fiatToBTC;
module.exports.satoshiToBTC = satoshiToBTC;
module.exports.BTCToLocalCurrency = BTCToLocalCurrency;
module.exports.setPrefferedCurrency = setPrefferedCurrency;
module.exports.getPreferredCurrency = getPreferredCurrency;
module.exports.btcToSatoshi = btcToSatoshi;
module.exports.getCurrencySymbol = getCurrencySymbol;
module.exports._setPreferredFiatCurrency = _setPreferredFiatCurrency; // export it to mock data in tests
module.exports._setExchangeRate = _setExchangeRate; // export it to mock data in tests
module.exports._setSkipUpdateExchangeRate = _setSkipUpdateExchangeRate; // export it to mock data in tests
module.exports.PREFERRED_CURRENCY = PREFERRED_CURRENCY_STORAGE_KEY;
module.exports.EXCHANGE_RATES = EXCHANGE_RATES_STORAGE_KEY;
module.exports.LAST_UPDATED = LAST_UPDATED;
module.exports.mostRecentFetchedRate = mostRecentFetchedRate;
module.exports.isRateOutdated = isRateOutdated;

230
blue_modules/currency.ts Normal file
View file

@ -0,0 +1,230 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import DefaultPreference from 'react-native-default-preference';
import * as RNLocalize from 'react-native-localize';
import BigNumber from 'bignumber.js';
import { FiatUnit, FiatUnitType, getFiatRate } from '../models/fiatUnit';
import WidgetCommunication from './WidgetCommunication';
const PREFERRED_CURRENCY_STORAGE_KEY = 'preferredCurrency';
const EXCHANGE_RATES_STORAGE_KEY = 'exchangeRates';
const LAST_UPDATED = 'LAST_UPDATED';
const GROUP_IO_BLUEWALLET = 'group.io.bluewallet.bluewallet';
const BTC_PREFIX = 'BTC_';
export interface CurrencyRate {
LastUpdated: Date | null;
Rate: number | string | null;
}
interface ExchangeRates {
[key: string]: number | boolean | undefined;
LAST_UPDATED_ERROR: boolean;
}
let preferredFiatCurrency: FiatUnitType = FiatUnit.USD;
let exchangeRates: ExchangeRates = { LAST_UPDATED_ERROR: false };
let lastTimeUpdateExchangeRateWasCalled: number = 0;
let skipUpdateExchangeRate: boolean = false;
async function setPreferredCurrency(item: FiatUnitType): Promise<void> {
await AsyncStorage.setItem(PREFERRED_CURRENCY_STORAGE_KEY, JSON.stringify(item));
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
await DefaultPreference.set(PREFERRED_CURRENCY_STORAGE_KEY, item.endPointKey);
await DefaultPreference.set('preferredCurrencyLocale', item.locale.replace('-', '_'));
// @ts-ignore: Convert to TSX later
WidgetCommunication.reloadAllTimelines();
}
async function getPreferredCurrency(): Promise<FiatUnitType> {
const preferredCurrency = JSON.parse((await AsyncStorage.getItem(PREFERRED_CURRENCY_STORAGE_KEY)) || '{}');
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
await DefaultPreference.set(PREFERRED_CURRENCY_STORAGE_KEY, preferredCurrency.endPointKey);
await DefaultPreference.set('preferredCurrencyLocale', preferredCurrency.locale.replace('-', '_'));
return preferredCurrency;
}
async function _restoreSavedExchangeRatesFromStorage(): Promise<void> {
try {
const rates = await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY);
exchangeRates = rates ? JSON.parse(rates) : { LAST_UPDATED_ERROR: false };
} catch (_) {
exchangeRates = { LAST_UPDATED_ERROR: false };
}
}
async function _restoreSavedPreferredFiatCurrencyFromStorage(): Promise<void> {
try {
const storedCurrency = await AsyncStorage.getItem(PREFERRED_CURRENCY_STORAGE_KEY);
if (!storedCurrency) throw new Error('No Preferred Fiat selected');
preferredFiatCurrency = JSON.parse(storedCurrency);
if (!FiatUnit[preferredFiatCurrency.endPointKey]) {
throw new Error('Invalid Fiat Unit');
}
} catch (_) {
const deviceCurrencies = RNLocalize.getCurrencies();
preferredFiatCurrency = deviceCurrencies[0] && FiatUnit[deviceCurrencies[0]] ? FiatUnit[deviceCurrencies[0]] : FiatUnit.USD;
}
}
async function updateExchangeRate(): Promise<void> {
if (skipUpdateExchangeRate) return;
if (Date.now() - lastTimeUpdateExchangeRateWasCalled <= 10000) {
// simple debounce so there's no race conditions
return;
}
lastTimeUpdateExchangeRateWasCalled = Date.now();
const lastUpdated = exchangeRates[LAST_UPDATED] as number | undefined;
if (lastUpdated && Date.now() - lastUpdated <= 30 * 60 * 1000) {
// not updating too often
return;
}
console.log('updating exchange rate...');
try {
const rate = await getFiatRate(preferredFiatCurrency.endPointKey);
exchangeRates[LAST_UPDATED] = Date.now();
exchangeRates[BTC_PREFIX + preferredFiatCurrency.endPointKey] = rate;
exchangeRates.LAST_UPDATED_ERROR = false;
await AsyncStorage.setItem(EXCHANGE_RATES_STORAGE_KEY, JSON.stringify(exchangeRates));
} catch (error) {
console.error('Error encountered when attempting to update exchange rate...', error);
const rate = JSON.parse((await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY)) || '{}');
rate.LAST_UPDATED_ERROR = true;
exchangeRates.LAST_UPDATED_ERROR = true;
await AsyncStorage.setItem(EXCHANGE_RATES_STORAGE_KEY, JSON.stringify(rate));
}
}
async function isRateOutdated(): Promise<boolean> {
try {
const rate = JSON.parse((await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY)) || '{}');
return rate.LAST_UPDATED_ERROR || Date.now() - (rate[LAST_UPDATED] || 0) >= 31 * 60 * 1000;
} catch {
return true;
}
}
async function initCurrencyDaemon(clearLastUpdatedTime: boolean = false): Promise<void> {
await _restoreSavedExchangeRatesFromStorage();
await _restoreSavedPreferredFiatCurrencyFromStorage();
if (clearLastUpdatedTime) {
exchangeRates[LAST_UPDATED] = 0;
lastTimeUpdateExchangeRateWasCalled = 0;
}
await updateExchangeRate();
}
function satoshiToLocalCurrency(satoshi: number, format: boolean = true): string {
const exchangeRateKey = BTC_PREFIX + preferredFiatCurrency.endPointKey;
const exchangeRate = exchangeRates[exchangeRateKey];
if (typeof exchangeRate !== 'number') {
updateExchangeRate();
return '...';
}
const btcAmount = new BigNumber(satoshi).dividedBy(100000000);
const convertedAmount = btcAmount.multipliedBy(exchangeRate);
let formattedAmount: string;
if (convertedAmount.isGreaterThanOrEqualTo(0.005) || convertedAmount.isLessThanOrEqualTo(-0.005)) {
formattedAmount = convertedAmount.toFixed(2);
} else {
formattedAmount = convertedAmount.toPrecision(2);
}
if (format === false) return formattedAmount;
try {
const formatter = new Intl.NumberFormat(preferredFiatCurrency.locale, {
style: 'currency',
currency: preferredFiatCurrency.endPointKey,
minimumFractionDigits: 2,
maximumFractionDigits: 8,
});
return formatter.format(Number(formattedAmount));
} catch (error) {
console.warn(error);
return formattedAmount;
}
}
function BTCToLocalCurrency(bitcoin: BigNumber.Value): string {
const sat = new BigNumber(bitcoin).multipliedBy(100000000).toNumber();
return satoshiToLocalCurrency(sat);
}
async function mostRecentFetchedRate(): Promise<CurrencyRate> {
const currencyInformation = JSON.parse((await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY)) || '{}');
const formatter = new Intl.NumberFormat(preferredFiatCurrency.locale, {
style: 'currency',
currency: preferredFiatCurrency.endPointKey,
});
const rate = currencyInformation[BTC_PREFIX + preferredFiatCurrency.endPointKey];
return {
LastUpdated: currencyInformation[LAST_UPDATED],
Rate: rate ? formatter.format(rate) : '...',
};
}
function satoshiToBTC(satoshi: number): string {
return new BigNumber(satoshi).dividedBy(100000000).toString(10);
}
function btcToSatoshi(btc: BigNumber.Value): number {
return new BigNumber(btc).multipliedBy(100000000).toNumber();
}
function fiatToBTC(fiatFloat: number): string {
const exchangeRateKey = BTC_PREFIX + preferredFiatCurrency.endPointKey;
const exchangeRate = exchangeRates[exchangeRateKey];
if (typeof exchangeRate !== 'number') {
throw new Error('Exchange rate not available');
}
const btcAmount = new BigNumber(fiatFloat).dividedBy(exchangeRate);
return btcAmount.toFixed(8);
}
function getCurrencySymbol(): string {
return preferredFiatCurrency.symbol;
}
function _setPreferredFiatCurrency(currency: FiatUnitType): void {
preferredFiatCurrency = currency;
}
function _setExchangeRate(pair: string, rate: number): void {
exchangeRates[pair] = rate;
}
function _setSkipUpdateExchangeRate(): void {
skipUpdateExchangeRate = true;
}
export {
updateExchangeRate,
initCurrencyDaemon,
satoshiToLocalCurrency,
fiatToBTC,
satoshiToBTC,
BTCToLocalCurrency,
setPreferredCurrency,
getPreferredCurrency,
btcToSatoshi,
getCurrencySymbol,
_setPreferredFiatCurrency,
_setExchangeRate,
_setSkipUpdateExchangeRate,
PREFERRED_CURRENCY_STORAGE_KEY,
EXCHANGE_RATES_STORAGE_KEY,
LAST_UPDATED,
mostRecentFetchedRate,
isRateOutdated,
};

View file

@ -7,9 +7,9 @@ import loc, { STORAGE_KEY as LOC_STORAGE_KEY } from '../loc';
import { LegacyWallet, WatchOnlyWallet } from '../class'; import { LegacyWallet, WatchOnlyWallet } from '../class';
import alert from '../components/Alert'; import alert from '../components/Alert';
import triggerHapticFeedback, { HapticFeedbackTypes } from './hapticFeedback'; import triggerHapticFeedback, { HapticFeedbackTypes } from './hapticFeedback';
import { PREFERRED_CURRENCY_STORAGE_KEY } from './currency';
const BlueApp = require('../BlueApp'); const BlueApp = require('../BlueApp');
const BlueElectrum = require('./BlueElectrum'); const BlueElectrum = require('./BlueElectrum');
const currency = require('../blue_modules/currency');
const A = require('../blue_modules/analytics'); const A = require('../blue_modules/analytics');
const _lastTimeTriedToRefetchWallet = {}; // hashmap of timestamps we _started_ refetching some wallet const _lastTimeTriedToRefetchWallet = {}; // hashmap of timestamps we _started_ refetching some wallet
@ -23,7 +23,7 @@ export const BlueStorageProvider = ({ children }) => {
const [walletsInitialized, setWalletsInitialized] = useState(false); const [walletsInitialized, setWalletsInitialized] = useState(false);
const [preferredFiatCurrency, _setPreferredFiatCurrency] = useState(FiatUnit.USD); const [preferredFiatCurrency, _setPreferredFiatCurrency] = useState(FiatUnit.USD);
const [language, _setLanguage] = useState(); const [language, _setLanguage] = useState();
const getPreferredCurrencyAsyncStorage = useAsyncStorage(currency.PREFERRED_CURRENCY).getItem; const getPreferredCurrencyAsyncStorage = useAsyncStorage(PREFERRED_CURRENCY_STORAGE_KEY).getItem;
const getLanguageAsyncStorage = useAsyncStorage(LOC_STORAGE_KEY).getItem; const getLanguageAsyncStorage = useAsyncStorage(LOC_STORAGE_KEY).getItem;
const [isHandOffUseEnabled, setIsHandOffUseEnabled] = useState(false); const [isHandOffUseEnabled, setIsHandOffUseEnabled] = useState(false);
const [isElectrumDisabled, setIsElectrumDisabled] = useState(true); const [isElectrumDisabled, setIsElectrumDisabled] = useState(true);

View file

@ -10,7 +10,14 @@ import loc, { formatBalanceWithoutSuffix, formatBalancePlain, removeTrailingZero
import { BlueText } from '../BlueComponents'; import { BlueText } from '../BlueComponents';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useTheme } from './themes'; import { useTheme } from './themes';
const currency = require('../blue_modules/currency'); import {
fiatToBTC,
getCurrencySymbol,
isRateOutdated,
mostRecentFetchedRate,
satoshiToBTC,
updateExchangeRate,
} from '../blue_modules/currency';
dayjs.extend(require('dayjs/plugin/localizedFormat')); dayjs.extend(require('dayjs/plugin/localizedFormat'));
class AmountInput extends Component { class AmountInput extends Component {
@ -57,13 +64,12 @@ class AmountInput extends Component {
} }
componentDidMount() { componentDidMount() {
currency mostRecentFetchedRate()
.mostRecentFetchedRate() .then(mostRecentFetchedRateValue => {
.then(mostRecentFetchedRate => { this.setState({ mostRecentFetchedRate: mostRecentFetchedRateValue });
this.setState({ mostRecentFetchedRate });
}) })
.finally(() => { .finally(() => {
currency.isRateOutdated().then(isRateOutdated => this.setState({ isRateOutdated })); isRateOutdated().then(isRateOutdatedValue => this.setState({ isRateOutdated: isRateOutdatedValue }));
}); });
} }
@ -86,7 +92,7 @@ class AmountInput extends Component {
sats = amount; sats = amount;
break; break;
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
sats = new BigNumber(currency.fiatToBTC(amount)).multipliedBy(100000000).toString(); sats = new BigNumber(fiatToBTC(amount)).multipliedBy(100000000).toString();
break; break;
} }
if (previousUnit === BitcoinUnit.LOCAL_CURRENCY && AmountInput.conversionCache[amount + previousUnit]) { if (previousUnit === BitcoinUnit.LOCAL_CURRENCY && AmountInput.conversionCache[amount + previousUnit]) {
@ -191,14 +197,14 @@ class AmountInput extends Component {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
this.setState({ isRateBeingUpdated: true }, async () => { this.setState({ isRateBeingUpdated: true }, async () => {
try { try {
await currency.updateExchangeRate(); await updateExchangeRate();
currency.mostRecentFetchedRate().then(mostRecentFetchedRate => { mostRecentFetchedRate().then(mostRecentFetchedRateValue => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
this.setState({ mostRecentFetchedRate }); this.setState({ mostRecentFetchedRate: mostRecentFetchedRateValue });
}); });
} finally { } finally {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
this.setState({ isRateBeingUpdated: false, isRateOutdated: await currency.isRateOutdated() }); this.setState({ isRateBeingUpdated: false, isRateOutdated: await isRateOutdated() });
} }
}); });
}; };
@ -220,11 +226,11 @@ class AmountInput extends Component {
secondaryDisplayCurrency = formatBalanceWithoutSuffix((isNaN(amount) ? 0 : amount).toString(), BitcoinUnit.LOCAL_CURRENCY, false); secondaryDisplayCurrency = formatBalanceWithoutSuffix((isNaN(amount) ? 0 : amount).toString(), BitcoinUnit.LOCAL_CURRENCY, false);
break; break;
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
secondaryDisplayCurrency = currency.fiatToBTC(parseFloat(isNaN(amount) ? 0 : amount)); secondaryDisplayCurrency = fiatToBTC(parseFloat(isNaN(amount) ? 0 : amount));
if (AmountInput.conversionCache[isNaN(amount) ? 0 : amount + BitcoinUnit.LOCAL_CURRENCY]) { if (AmountInput.conversionCache[isNaN(amount) ? 0 : amount + BitcoinUnit.LOCAL_CURRENCY]) {
// cache hit! we reuse old value that supposedly doesn't have rounding errors // cache hit! we reuse old value that supposedly doesn't have rounding errors
const sats = AmountInput.conversionCache[isNaN(amount) ? 0 : amount + BitcoinUnit.LOCAL_CURRENCY]; const sats = AmountInput.conversionCache[isNaN(amount) ? 0 : amount + BitcoinUnit.LOCAL_CURRENCY];
secondaryDisplayCurrency = currency.satoshiToBTC(sats); secondaryDisplayCurrency = satoshiToBTC(sats);
} }
break; break;
} }
@ -251,7 +257,7 @@ class AmountInput extends Component {
<View style={styles.flex}> <View style={styles.flex}>
<View style={styles.container}> <View style={styles.container}>
{unit === BitcoinUnit.LOCAL_CURRENCY && amount !== BitcoinUnit.MAX && ( {unit === BitcoinUnit.LOCAL_CURRENCY && amount !== BitcoinUnit.MAX && (
<Text style={[styles.localCurrency, stylesHook.localCurrency]}>{currency.getCurrencySymbol() + ' '}</Text> <Text style={[styles.localCurrency, stylesHook.localCurrency]}>{getCurrencySymbol() + ' '}</Text>
)} )}
{amount !== BitcoinUnit.MAX ? ( {amount !== BitcoinUnit.MAX ? (
<TextInput <TextInput

View file

@ -65,7 +65,10 @@ const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps>
}, [wallet, verifyIfWalletAllowsOnchainAddress]); }, [wallet, verifyIfWalletAllowsOnchainAddress]);
const handleCopyPress = () => { const handleCopyPress = () => {
Clipboard.setString(formatBalance(wallet.getBalance(), wallet.getPreferredBalanceUnit()).toString()); const value = formatBalance(wallet.getBalance(), wallet.getPreferredBalanceUnit());
if (value) {
Clipboard.setString(value);
}
}; };
const updateWalletVisibility = (w: AbstractWallet, newHideBalance: boolean) => { const updateWalletVisibility = (w: AbstractWallet, newHideBalance: boolean) => {
@ -134,8 +137,8 @@ const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps>
const balance = useMemo(() => { const balance = useMemo(() => {
const hideBalance = wallet.hideBalance; const hideBalance = wallet.hideBalance;
const balanceUnit = wallet.getPreferredBalanceUnit(); const balanceUnit = wallet.getPreferredBalanceUnit();
const balanceFormatted = formatBalance(wallet.getBalance(), balanceUnit, true).toString(); const balanceFormatted = formatBalance(wallet.getBalance(), balanceUnit, true);
return !hideBalance && balanceFormatted; return !hideBalance && balanceFormatted?.toString();
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [wallet.hideBalance, wallet.getPreferredBalanceUnit()]); }, [wallet.hideBalance, wallet.getPreferredBalanceUnit()]);
@ -211,6 +214,7 @@ const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps>
) : ( ) : (
<Text <Text
testID="WalletBalance" testID="WalletBalance"
// @ts-ignore: Ugh
key={balance} // force component recreation on balance change. To fix right-to-left languages, like Farsi key={balance} // force component recreation on balance change. To fix right-to-left languages, like Farsi
numberOfLines={1} numberOfLines={1}
adjustsFontSizeToFit adjustsFontSizeToFit

View file

@ -9,7 +9,7 @@ import BigNumber from 'bignumber.js';
import { BitcoinUnit } from '../models/bitcoinUnits'; import { BitcoinUnit } from '../models/bitcoinUnits';
import { AvailableLanguages } from './languages'; import { AvailableLanguages } from './languages';
import { I18nManager } from 'react-native'; import { I18nManager } from 'react-native';
const currency = require('../blue_modules/currency'); import { satoshiToLocalCurrency } from '../blue_modules/currency';
export const STORAGE_KEY = 'lang'; export const STORAGE_KEY = 'lang';
@ -310,7 +310,7 @@ export function formatBalance(balance: number, toUnit: string, withFormatting =
} else if (toUnit === BitcoinUnit.SATS) { } else if (toUnit === BitcoinUnit.SATS) {
return (withFormatting ? new Intl.NumberFormat().format(balance).toString() : String(balance)) + ' ' + loc.units[BitcoinUnit.SATS]; return (withFormatting ? new Intl.NumberFormat().format(balance).toString() : String(balance)) + ' ' + loc.units[BitcoinUnit.SATS];
} else if (toUnit === BitcoinUnit.LOCAL_CURRENCY) { } else if (toUnit === BitcoinUnit.LOCAL_CURRENCY) {
return currency.satoshiToLocalCurrency(balance); return satoshiToLocalCurrency(balance);
} }
} }
@ -332,7 +332,7 @@ export function formatBalanceWithoutSuffix(balance = 0, toUnit: string, withForm
} else if (toUnit === BitcoinUnit.SATS) { } else if (toUnit === BitcoinUnit.SATS) {
return withFormatting ? new Intl.NumberFormat().format(balance).toString() : String(balance); return withFormatting ? new Intl.NumberFormat().format(balance).toString() : String(balance);
} else if (toUnit === BitcoinUnit.LOCAL_CURRENCY) { } else if (toUnit === BitcoinUnit.LOCAL_CURRENCY) {
return currency.satoshiToLocalCurrency(balance); return satoshiToLocalCurrency(balance);
} }
} }
return balance.toString(); return balance.toString();
@ -349,7 +349,7 @@ export function formatBalanceWithoutSuffix(balance = 0, toUnit: string, withForm
export function formatBalancePlain(balance = 0, toUnit: string, withFormatting = false) { export function formatBalancePlain(balance = 0, toUnit: string, withFormatting = false) {
const newInputValue = formatBalanceWithoutSuffix(balance, toUnit, withFormatting); const newInputValue = formatBalanceWithoutSuffix(balance, toUnit, withFormatting);
// eslint-disable-next-line @typescript-eslint/no-use-before-define // eslint-disable-next-line @typescript-eslint/no-use-before-define
return _leaveNumbersAndDots(newInputValue); return _leaveNumbersAndDots(newInputValue.toString());
} }
export function _leaveNumbersAndDots(newInputValue: string) { export function _leaveNumbersAndDots(newInputValue: string) {

View file

@ -18,7 +18,7 @@ import { useTheme } from '../../components/themes';
import Button from '../../components/Button'; import Button from '../../components/Button';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback'; import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import SafeArea from '../../components/SafeArea'; import SafeArea from '../../components/SafeArea';
const currency = require('../../blue_modules/currency'); import { btcToSatoshi, fiatToBTC } from '../../blue_modules/currency';
type LdkOpenChannelProps = RouteProp< type LdkOpenChannelProps = RouteProp<
{ {
@ -223,11 +223,11 @@ const LdkOpenChannel = (props: any) => {
amountSats = parseInt(fundingAmount.amount, 10); amountSats = parseInt(fundingAmount.amount, 10);
break; break;
case BitcoinUnit.BTC: case BitcoinUnit.BTC:
amountSats = currency.btcToSatoshi(fundingAmount.amount); amountSats = btcToSatoshi(fundingAmount.amount);
break; break;
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
// also accounting for cached fiat->sat conversion to avoid rounding error // also accounting for cached fiat->sat conversion to avoid rounding error
amountSats = currency.btcToSatoshi(currency.fiatToBTC(fundingAmount.amount)); amountSats = btcToSatoshi(fiatToBTC(fundingAmount.amount));
break; break;
} }
setFundingAmount({ amount: fundingAmount.amount, amountSats }); setFundingAmount({ amount: fundingAmount.amount, amountSats });
@ -237,10 +237,10 @@ const LdkOpenChannel = (props: any) => {
let amountSats = fundingAmount.amountSats; let amountSats = fundingAmount.amountSats;
switch (unit) { switch (unit) {
case BitcoinUnit.BTC: case BitcoinUnit.BTC:
amountSats = currency.btcToSatoshi(text); amountSats = btcToSatoshi(text);
break; break;
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
amountSats = currency.btcToSatoshi(currency.fiatToBTC(text)); amountSats = btcToSatoshi(fiatToBTC(Number(text)));
break; break;
case BitcoinUnit.SATS: case BitcoinUnit.SATS:
amountSats = parseInt(text, 10); amountSats = parseInt(text, 10);

View file

@ -31,7 +31,7 @@ import { requestCameraAuthorization } from '../../helpers/scan-qr';
import { useTheme } from '../../components/themes'; import { useTheme } from '../../components/themes';
import Button from '../../components/Button'; import Button from '../../components/Button';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback'; import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
const currency = require('../../blue_modules/currency'); import { btcToSatoshi, fiatToBTC, satoshiToBTC } from '../../blue_modules/currency';
const LNDCreateInvoice = () => { const LNDCreateInvoice = () => {
const { wallets, saveToDisk, setSelectedWalletID } = useContext(BlueStorageContext); const { wallets, saveToDisk, setSelectedWalletID } = useContext(BlueStorageContext);
@ -156,11 +156,11 @@ const LNDCreateInvoice = () => {
invoiceAmount = parseInt(invoiceAmount, 10); // basically nop invoiceAmount = parseInt(invoiceAmount, 10); // basically nop
break; break;
case BitcoinUnit.BTC: case BitcoinUnit.BTC:
invoiceAmount = currency.btcToSatoshi(invoiceAmount); invoiceAmount = btcToSatoshi(invoiceAmount);
break; break;
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
// trying to fetch cached sat equivalent for this fiat amount // trying to fetch cached sat equivalent for this fiat amount
invoiceAmount = AmountInput.getCachedSatoshis(invoiceAmount) || currency.btcToSatoshi(currency.fiatToBTC(invoiceAmount)); invoiceAmount = AmountInput.getCachedSatoshis(invoiceAmount) || btcToSatoshi(fiatToBTC(invoiceAmount));
break; break;
} }
@ -285,7 +285,7 @@ const LNDCreateInvoice = () => {
// nop // nop
break; break;
case BitcoinUnit.BTC: case BitcoinUnit.BTC:
newAmount = currency.satoshiToBTC(newAmount); newAmount = satoshiToBTC(newAmount);
break; break;
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
newAmount = formatBalancePlain(newAmount, BitcoinUnit.LOCAL_CURRENCY); newAmount = formatBalancePlain(newAmount, BitcoinUnit.LOCAL_CURRENCY);

View file

@ -17,8 +17,8 @@ import { useTheme } from '../../components/themes';
import Button from '../../components/Button'; import Button from '../../components/Button';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback'; import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import SafeArea from '../../components/SafeArea'; import SafeArea from '../../components/SafeArea';
import { btcToSatoshi, fiatToBTC, satoshiToBTC, satoshiToLocalCurrency } from '../../blue_modules/currency';
const prompt = require('../../helpers/prompt'); const prompt = require('../../helpers/prompt');
const currency = require('../../blue_modules/currency');
/** /**
* if user has default currency - fiat, attempting to pay will trigger conversion from entered in input field fiat value * if user has default currency - fiat, attempting to pay will trigger conversion from entered in input field fiat value
@ -86,10 +86,10 @@ const LnurlPay = () => {
} }
switch (unit) { switch (unit) {
case BitcoinUnit.BTC: case BitcoinUnit.BTC:
newAmount = currency.satoshiToBTC(newAmount); newAmount = satoshiToBTC(newAmount);
break; break;
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
newAmount = currency.satoshiToLocalCurrency(newAmount, false); newAmount = satoshiToLocalCurrency(newAmount, false);
_cacheFiatToSat[newAmount] = originalSatAmount; _cacheFiatToSat[newAmount] = originalSatAmount;
break; break;
} }
@ -120,13 +120,13 @@ const LnurlPay = () => {
amountSats = parseInt(amountSats, 10); // nop amountSats = parseInt(amountSats, 10); // nop
break; break;
case BitcoinUnit.BTC: case BitcoinUnit.BTC:
amountSats = currency.btcToSatoshi(amountSats); amountSats = btcToSatoshi(amountSats);
break; break;
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
if (_cacheFiatToSat[amount]) { if (_cacheFiatToSat[amount]) {
amountSats = _cacheFiatToSat[amount]; amountSats = _cacheFiatToSat[amount];
} else { } else {
amountSats = currency.btcToSatoshi(currency.fiatToBTC(amountSats)); amountSats = btcToSatoshi(fiatToBTC(amountSats));
} }
break; break;
} }

View file

@ -27,7 +27,7 @@ import { useTheme } from '../../components/themes';
import Button from '../../components/Button'; import Button from '../../components/Button';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback'; import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import SafeArea from '../../components/SafeArea'; import SafeArea from '../../components/SafeArea';
const currency = require('../../blue_modules/currency'); import { btcToSatoshi, fiatToBTC } from '../../blue_modules/currency';
const ScanLndInvoice = () => { const ScanLndInvoice = () => {
const { wallets, fetchAndSaveWalletTransactions } = useContext(BlueStorageContext); const { wallets, fetchAndSaveWalletTransactions } = useContext(BlueStorageContext);
@ -182,10 +182,10 @@ const ScanLndInvoice = () => {
amountSats = parseInt(amountSats, 10); // nop amountSats = parseInt(amountSats, 10); // nop
break; break;
case BitcoinUnit.BTC: case BitcoinUnit.BTC:
amountSats = currency.btcToSatoshi(amountSats); amountSats = btcToSatoshi(amountSats);
break; break;
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
amountSats = currency.btcToSatoshi(currency.fiatToBTC(amountSats)); amountSats = btcToSatoshi(fiatToBTC(amountSats));
break; break;
} }
setIsLoading(true); setIsLoading(true);

View file

@ -38,7 +38,7 @@ import { SuccessView } from '../send/success';
import { useTheme } from '../../components/themes'; import { useTheme } from '../../components/themes';
import Button from '../../components/Button'; import Button from '../../components/Button';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback'; import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
const currency = require('../../blue_modules/currency'); import { fiatToBTC, satoshiToBTC } from '../../blue_modules/currency';
const ReceiveDetails = () => { const ReceiveDetails = () => {
const { walletID, address } = useRoute().params; const { walletID, address } = useRoute().params;
@ -385,14 +385,14 @@ const ReceiveDetails = () => {
// nop // nop
break; break;
case BitcoinUnit.SATS: case BitcoinUnit.SATS:
amount = currency.satoshiToBTC(customAmount); amount = satoshiToBTC(customAmount);
break; break;
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
if (AmountInput.conversionCache[amount + BitcoinUnit.LOCAL_CURRENCY]) { if (AmountInput.conversionCache[amount + BitcoinUnit.LOCAL_CURRENCY]) {
// cache hit! we reuse old value that supposedly doesnt have rounding errors // cache hit! we reuse old value that supposedly doesnt have rounding errors
amount = currency.satoshiToBTC(AmountInput.conversionCache[amount + BitcoinUnit.LOCAL_CURRENCY]); amount = satoshiToBTC(AmountInput.conversionCache[amount + BitcoinUnit.LOCAL_CURRENCY]);
} else { } else {
amount = currency.fiatToBTC(customAmount); amount = fiatToBTC(customAmount);
} }
break; break;
} }
@ -447,9 +447,9 @@ const ReceiveDetails = () => {
case BitcoinUnit.BTC: case BitcoinUnit.BTC:
return customAmount + ' BTC'; return customAmount + ' BTC';
case BitcoinUnit.SATS: case BitcoinUnit.SATS:
return currency.satoshiToBTC(customAmount) + ' BTC'; return satoshiToBTC(customAmount) + ' BTC';
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
return currency.fiatToBTC(customAmount) + ' BTC'; return fiatToBTC(customAmount) + ' BTC';
} }
return customAmount + ' ' + customUnit; return customAmount + ' ' + customUnit;
} else { } else {

View file

@ -17,7 +17,7 @@ import { useTheme } from '../../components/themes';
import Button from '../../components/Button'; import Button from '../../components/Button';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback'; import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import SafeArea from '../../components/SafeArea'; import SafeArea from '../../components/SafeArea';
const currency = require('../../blue_modules/currency'); import { satoshiToBTC, satoshiToLocalCurrency } from '../../blue_modules/currency';
const BlueElectrum = require('../../blue_modules/BlueElectrum'); const BlueElectrum = require('../../blue_modules/BlueElectrum');
const Bignumber = require('bignumber.js'); const Bignumber = require('bignumber.js');
const bitcoin = require('bitcoinjs-lib'); const bitcoin = require('bitcoinjs-lib');
@ -182,11 +182,11 @@ const Confirm = () => {
<> <>
<View style={styles.valueWrap}> <View style={styles.valueWrap}>
<Text testID="TransactionValue" style={[styles.valueValue, stylesHook.valueValue]}> <Text testID="TransactionValue" style={[styles.valueValue, stylesHook.valueValue]}>
{currency.satoshiToBTC(item.value)} {satoshiToBTC(item.value)}
</Text> </Text>
<Text style={[styles.valueUnit, stylesHook.valueValue]}>{' ' + loc.units[BitcoinUnit.BTC]}</Text> <Text style={[styles.valueUnit, stylesHook.valueValue]}>{' ' + loc.units[BitcoinUnit.BTC]}</Text>
</View> </View>
<Text style={[styles.transactionAmountFiat, stylesHook.transactionAmountFiat]}>{currency.satoshiToLocalCurrency(item.value)}</Text> <Text style={[styles.transactionAmountFiat, stylesHook.transactionAmountFiat]}>{satoshiToLocalCurrency(item.value)}</Text>
<BlueCard> <BlueCard>
<Text style={[styles.transactionDetailsTitle, stylesHook.transactionDetailsTitle]}>{loc.send.create_to}</Text> <Text style={[styles.transactionDetailsTitle, stylesHook.transactionDetailsTitle]}>{loc.send.create_to}</Text>
<Text testID="TransactionAddress" style={[styles.transactionDetailsSubtitle, stylesHook.transactionDetailsSubtitle]}> <Text testID="TransactionAddress" style={[styles.transactionDetailsSubtitle, stylesHook.transactionDetailsSubtitle]}>
@ -233,7 +233,7 @@ const Confirm = () => {
<View style={styles.cardBottom}> <View style={styles.cardBottom}>
<BlueCard> <BlueCard>
<Text style={styles.cardText} testID="TransactionFee"> <Text style={styles.cardText} testID="TransactionFee">
{loc.send.create_fee}: {formatBalance(feeSatoshi, BitcoinUnit.BTC)} ({currency.satoshiToLocalCurrency(feeSatoshi)}) {loc.send.create_fee}: {formatBalance(feeSatoshi, BitcoinUnit.BTC)} ({satoshiToLocalCurrency(feeSatoshi)})
</Text> </Text>
{isLoading ? <ActivityIndicator /> : <Button disabled={isElectrumDisabled} onPress={send} title={loc.send.confirm_sendNow} />} {isLoading ? <ActivityIndicator /> : <Button disabled={isElectrumDisabled} onPress={send} title={loc.send.confirm_sendNow} />}
</BlueCard> </BlueCard>

View file

@ -17,8 +17,8 @@ import { useNavigation, useRoute } from '@react-navigation/native';
import alert from '../../components/Alert'; import alert from '../../components/Alert';
import { PERMISSIONS, RESULTS, request } from 'react-native-permissions'; import { PERMISSIONS, RESULTS, request } from 'react-native-permissions';
import { useTheme } from '../../components/themes'; import { useTheme } from '../../components/themes';
import { satoshiToBTC } from '../../blue_modules/currency';
const bitcoin = require('bitcoinjs-lib'); const bitcoin = require('bitcoinjs-lib');
const currency = require('../../blue_modules/currency');
const SendCreate = () => { const SendCreate = () => {
const { fee, recipients, memo = '', satoshiPerByte, psbt, showAnimatedQr, tx } = useRoute().params; const { fee, recipients, memo = '', satoshiPerByte, psbt, showAnimatedQr, tx } = useRoute().params;
@ -116,7 +116,7 @@ const SendCreate = () => {
<Text style={[styles.transactionDetailsSubtitle, styleHooks.transactionDetailsSubtitle]}>{item.address}</Text> <Text style={[styles.transactionDetailsSubtitle, styleHooks.transactionDetailsSubtitle]}>{item.address}</Text>
<Text style={[styles.transactionDetailsTitle, styleHooks.transactionDetailsTitle]}>{loc.send.create_amount}</Text> <Text style={[styles.transactionDetailsTitle, styleHooks.transactionDetailsTitle]}>{loc.send.create_amount}</Text>
<Text style={[styles.transactionDetailsSubtitle, styleHooks.transactionDetailsSubtitle]}> <Text style={[styles.transactionDetailsSubtitle, styleHooks.transactionDetailsSubtitle]}>
{currency.satoshiToBTC(item.value)} {BitcoinUnit.BTC} {satoshiToBTC(item.value)} {BitcoinUnit.BTC}
</Text> </Text>
{recipients.length > 1 && ( {recipients.length > 1 && (
<BlueText style={styles.itemOf}>{loc.formatString(loc._.of, { number: index + 1, total: recipients.length })}</BlueText> <BlueText style={styles.itemOf}>{loc.formatString(loc._.of, { number: index + 1, total: recipients.length })}</BlueText>

View file

@ -44,7 +44,7 @@ import { useTheme } from '../../components/themes';
import Button from '../../components/Button'; import Button from '../../components/Button';
import ListItem from '../../components/ListItem'; import ListItem from '../../components/ListItem';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback'; import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
const currency = require('../../blue_modules/currency'); import { btcToSatoshi, fiatToBTC } from '../../blue_modules/currency';
const prompt = require('../../helpers/prompt'); const prompt = require('../../helpers/prompt');
const fs = require('../../blue_modules/fs'); const fs = require('../../blue_modules/fs');
const btcAddressRx = /^[a-zA-Z0-9]{26,35}$/; const btcAddressRx = /^[a-zA-Z0-9]{26,35}$/;
@ -145,12 +145,12 @@ const SendDetails = () => {
currentAddress.address = address; currentAddress.address = address;
if (Number(amount) > 0) { if (Number(amount) > 0) {
currentAddress.amount = amount; currentAddress.amount = amount;
currentAddress.amountSats = currency.btcToSatoshi(amount); currentAddress.amountSats = btcToSatoshi(amount);
} }
addrs[scrollIndex.current] = currentAddress; addrs[scrollIndex.current] = currentAddress;
return [...addrs]; return [...addrs];
} else { } else {
return [...addrs, { address, amount, amountSats: currency.btcToSatoshi(amount), key: String(Math.random()) }]; return [...addrs, { address, amount, amountSats: btcToSatoshi(amount), key: String(Math.random()) }];
} }
}); });
@ -285,8 +285,8 @@ const SendDetails = () => {
if (value > 0) { if (value > 0) {
targets.push({ address: transaction.address, value }); targets.push({ address: transaction.address, value });
} else if (transaction.amount) { } else if (transaction.amount) {
if (currency.btcToSatoshi(transaction.amount) > 0) { if (btcToSatoshi(transaction.amount) > 0) {
targets.push({ address: transaction.address, value: currency.btcToSatoshi(transaction.amount) }); targets.push({ address: transaction.address, value: btcToSatoshi(transaction.amount) });
} }
} }
} }
@ -517,8 +517,8 @@ const SendDetails = () => {
if (value > 0) { if (value > 0) {
targets.push({ address: transaction.address, value }); targets.push({ address: transaction.address, value });
} else if (transaction.amount) { } else if (transaction.amount) {
if (currency.btcToSatoshi(transaction.amount) > 0) { if (btcToSatoshi(transaction.amount) > 0) {
targets.push({ address: transaction.address, value: currency.btcToSatoshi(transaction.amount) }); targets.push({ address: transaction.address, value: btcToSatoshi(transaction.amount) });
} }
} }
} }
@ -1329,11 +1329,11 @@ const SendDetails = () => {
addr.amountSats = parseInt(addr.amount, 10); addr.amountSats = parseInt(addr.amount, 10);
break; break;
case BitcoinUnit.BTC: case BitcoinUnit.BTC:
addr.amountSats = currency.btcToSatoshi(addr.amount); addr.amountSats = btcToSatoshi(addr.amount);
break; break;
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
// also accounting for cached fiat->sat conversion to avoid rounding error // also accounting for cached fiat->sat conversion to avoid rounding error
addr.amountSats = AmountInput.getCachedSatoshis(addr.amount) || currency.btcToSatoshi(currency.fiatToBTC(addr.amount)); addr.amountSats = AmountInput.getCachedSatoshis(addr.amount) || btcToSatoshi(fiatToBTC(addr.amount));
break; break;
} }
@ -1350,10 +1350,10 @@ const SendDetails = () => {
item.amount = text; item.amount = text;
switch (units[index] || amountUnit) { switch (units[index] || amountUnit) {
case BitcoinUnit.BTC: case BitcoinUnit.BTC:
item.amountSats = currency.btcToSatoshi(item.amount); item.amountSats = btcToSatoshi(item.amount);
break; break;
case BitcoinUnit.LOCAL_CURRENCY: case BitcoinUnit.LOCAL_CURRENCY:
item.amountSats = currency.btcToSatoshi(currency.fiatToBTC(item.amount)); item.amountSats = btcToSatoshi(fiatToBTC(item.amount));
break; break;
case BitcoinUnit.SATS: case BitcoinUnit.SATS:
default: default:

View file

@ -12,9 +12,9 @@ import alert from '../../components/Alert';
import { useTheme } from '../../components/themes'; import { useTheme } from '../../components/themes';
import Button from '../../components/Button'; import Button from '../../components/Button';
import SafeArea from '../../components/SafeArea'; import SafeArea from '../../components/SafeArea';
import { satoshiToBTC, satoshiToLocalCurrency } from '../../blue_modules/currency';
const bitcoin = require('bitcoinjs-lib'); const bitcoin = require('bitcoinjs-lib');
const BigNumber = require('bignumber.js'); const BigNumber = require('bignumber.js');
const currency = require('../../blue_modules/currency');
const shortenAddress = addr => { const shortenAddress = addr => {
return addr.substr(0, Math.floor(addr.length / 2) - 1) + '\n' + addr.substr(Math.floor(addr.length / 2) - 1, addr.length); return addr.substr(0, Math.floor(addr.length / 2) - 1) + '\n' + addr.substr(Math.floor(addr.length / 2) - 1, addr.length);
@ -81,7 +81,7 @@ const PsbtMultisig = () => {
} }
destination = shortenAddress(destination.join(', ')); destination = shortenAddress(destination.join(', '));
const totalBtc = new BigNumber(totalSat).dividedBy(100000000).toNumber(); const totalBtc = new BigNumber(totalSat).dividedBy(100000000).toNumber();
const totalFiat = currency.satoshiToLocalCurrency(totalSat); const totalFiat = satoshiToLocalCurrency(totalSat);
const getFee = () => { const getFee = () => {
return wallet.calculateFeeFromPsbt(psbt); return wallet.calculateFeeFromPsbt(psbt);
@ -252,9 +252,9 @@ const PsbtMultisig = () => {
<View style={styles.bottomWrapper}> <View style={styles.bottomWrapper}>
<View style={styles.bottomFeesWrapper}> <View style={styles.bottomFeesWrapper}>
<BlueText style={[styles.feeFiatText, stylesHook.feeFiatText]}> <BlueText style={[styles.feeFiatText, stylesHook.feeFiatText]}>
{loc.formatString(loc.multisig.fee, { number: currency.satoshiToLocalCurrency(getFee()) })} -{' '} {loc.formatString(loc.multisig.fee, { number: satoshiToLocalCurrency(getFee()) })} -{' '}
</BlueText> </BlueText>
<BlueText>{loc.formatString(loc.multisig.fee_btc, { number: currency.satoshiToBTC(getFee()) })}</BlueText> <BlueText>{loc.formatString(loc.multisig.fee_btc, { number: satoshiToBTC(getFee()) })}</BlueText>
</View> </View>
</View> </View>
<View style={styles.marginConfirmButton}> <View style={styles.marginConfirmButton}>

View file

@ -10,16 +10,17 @@ import dayjs from 'dayjs';
import alert from '../../components/Alert'; import alert from '../../components/Alert';
import { useTheme } from '../../components/themes'; import { useTheme } from '../../components/themes';
import ListItem from '../../components/ListItem'; import ListItem from '../../components/ListItem';
import {
CurrencyRate,
getPreferredCurrency,
initCurrencyDaemon,
mostRecentFetchedRate,
setPreferredCurrency,
} from '../../blue_modules/currency';
dayjs.extend(require('dayjs/plugin/calendar')); dayjs.extend(require('dayjs/plugin/calendar'));
const currency = require('../../blue_modules/currency');
const ITEM_HEIGHT = 50; const ITEM_HEIGHT = 50;
interface CurrencyRate {
LastUpdated: Date | null;
Rate: number | null;
}
const Currency: React.FC = () => { const Currency: React.FC = () => {
const { setPreferredFiatCurrency } = useContext(BlueStorageContext); const { setPreferredFiatCurrency } = useContext(BlueStorageContext);
const [isSavingNewPreferredCurrency, setIsSavingNewPreferredCurrency] = useState(false); const [isSavingNewPreferredCurrency, setIsSavingNewPreferredCurrency] = useState(false);
@ -39,18 +40,18 @@ const Currency: React.FC = () => {
}); });
const fetchCurrency = async () => { const fetchCurrency = async () => {
let preferredCurrency = FiatUnit.USD; let preferredCurrency;
try { try {
preferredCurrency = await currency.getPreferredCurrency(); preferredCurrency = await getPreferredCurrency();
if (preferredCurrency === null) { if (preferredCurrency === null) {
throw Error(); throw Error();
} }
setSelectedCurrency(preferredCurrency); setSelectedCurrency(preferredCurrency);
} catch (_error) { } catch (_error) {
setSelectedCurrency(preferredCurrency); setSelectedCurrency(FiatUnit.USD);
} }
const mostRecentFetchedRate = await currency.mostRecentFetchedRate(); const mostRecentFetchedRateValue = await mostRecentFetchedRate();
setCurrencyRate(mostRecentFetchedRate); setCurrencyRate(mostRecentFetchedRateValue);
}; };
useLayoutEffect(() => { useLayoutEffect(() => {
@ -78,8 +79,8 @@ const Currency: React.FC = () => {
setIsSavingNewPreferredCurrency(true); setIsSavingNewPreferredCurrency(true);
try { try {
await getFiatRate(item.endPointKey); await getFiatRate(item.endPointKey);
await currency.setPrefferedCurrency(item); await setPreferredCurrency(item);
await currency.init(true); await initCurrencyDaemon(true);
await fetchCurrency(); await fetchCurrency();
setSelectedCurrency(item); setSelectedCurrency(item);
setPreferredFiatCurrency(); setPreferredFiatCurrency();

View file

@ -2,49 +2,56 @@ import assert from 'assert';
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
import { FiatUnit } from '../../models/fiatUnit'; import { FiatUnit } from '../../models/fiatUnit';
import {
EXCHANGE_RATES_STORAGE_KEY,
LAST_UPDATED,
PREFERRED_CURRENCY_STORAGE_KEY,
getPreferredCurrency,
initCurrencyDaemon,
setPreferredCurrency,
} from '../../blue_modules/currency';
jest.setTimeout(90 * 1000); jest.setTimeout(90 * 1000);
describe('currency', () => { describe('currency', () => {
it('fetches exchange rate and saves to AsyncStorage', async () => { it('fetches exchange rate and saves to AsyncStorage', async () => {
const currency = require('../../blue_modules/currency'); await initCurrencyDaemon();
await currency.init(); let cur = await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY);
let cur = await AsyncStorage.getItem(currency.EXCHANGE_RATES);
cur = JSON.parse(cur); cur = JSON.parse(cur);
assert.ok(Number.isInteger(cur[currency.LAST_UPDATED])); assert.ok(Number.isInteger(cur[LAST_UPDATED]));
assert.ok(cur[currency.LAST_UPDATED] > 0); assert.ok(cur[LAST_UPDATED] > 0);
assert.ok(cur.BTC_USD > 0); assert.ok(cur.BTC_USD > 0);
// now, setting other currency as default // now, setting other currency as default
await AsyncStorage.setItem(currency.PREFERRED_CURRENCY, JSON.stringify(FiatUnit.JPY)); await AsyncStorage.setItem(PREFERRED_CURRENCY_STORAGE_KEY, JSON.stringify(FiatUnit.JPY));
await currency.init(true); await initCurrencyDaemon(true);
cur = JSON.parse(await AsyncStorage.getItem(currency.EXCHANGE_RATES)); cur = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
assert.ok(cur.BTC_JPY > 0); assert.ok(cur.BTC_JPY > 0);
// now setting with a proper setter // now setting with a proper setter
await currency.setPrefferedCurrency(FiatUnit.EUR); await setPreferredCurrency(FiatUnit.EUR);
await currency.init(true); await initCurrencyDaemon(true);
const preferred = await currency.getPreferredCurrency(); const preferred = await getPreferredCurrency();
assert.strictEqual(preferred.endPointKey, 'EUR'); assert.strictEqual(preferred.endPointKey, 'EUR');
cur = JSON.parse(await AsyncStorage.getItem(currency.EXCHANGE_RATES)); cur = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
assert.ok(cur.BTC_EUR > 0); assert.ok(cur.BTC_EUR > 0);
// test Yadio rate source // test Yadio rate source
await currency.setPrefferedCurrency(FiatUnit.ARS); await setPreferredCurrency(FiatUnit.ARS);
await currency.init(true); await initCurrencyDaemon(true);
cur = JSON.parse(await AsyncStorage.getItem(currency.EXCHANGE_RATES)); cur = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
assert.ok(cur.BTC_ARS > 0); assert.ok(cur.BTC_ARS > 0);
// test YadioConvert rate source // test YadioConvert rate source
await currency.setPrefferedCurrency(FiatUnit.LBP); await setPreferredCurrency(FiatUnit.LBP);
await currency.init(true); await initCurrencyDaemon(true);
cur = JSON.parse(await AsyncStorage.getItem(currency.EXCHANGE_RATES)); cur = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
assert.ok(cur.BTC_LBP > 0); assert.ok(cur.BTC_LBP > 0);
// test Exir rate source // test Exir rate source
await currency.setPrefferedCurrency(FiatUnit.IRT); await setPreferredCurrency(FiatUnit.IRT);
await currency.init(true); await initCurrencyDaemon(true);
cur = JSON.parse(await AsyncStorage.getItem(currency.EXCHANGE_RATES)); cur = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
assert.ok(cur.BTC_IRT > 0); assert.ok(cur.BTC_IRT > 0);
}); });
}); });

View file

@ -4,7 +4,7 @@ import { TABS } from '../../components/addresses/AddressTypeTabs';
jest.mock('../../blue_modules/currency', () => { jest.mock('../../blue_modules/currency', () => {
return { return {
init: jest.fn(), initCurrencyDaemon: jest.fn(),
}; };
}); });

View file

@ -1,36 +1,39 @@
import {
BTCToLocalCurrency,
_setExchangeRate,
_setPreferredFiatCurrency,
satoshiToBTC,
satoshiToLocalCurrency,
} from '../../blue_modules/currency';
import { FiatUnit } from '../../models/fiatUnit'; import { FiatUnit } from '../../models/fiatUnit';
const assert = require('assert'); const assert = require('assert');
describe('currency', () => { describe('currency', () => {
it('formats everything correctly', async () => { it('formats everything correctly', async () => {
const currency = require('../../blue_modules/currency'); _setExchangeRate('BTC_USD', 10000);
currency._setExchangeRate('BTC_USD', 10000);
assert.strictEqual(currency.satoshiToLocalCurrency(1), '$0.0001'); assert.strictEqual(satoshiToLocalCurrency(1), '$0.0001');
assert.strictEqual(currency.satoshiToLocalCurrency(-1), '-$0.0001'); assert.strictEqual(satoshiToLocalCurrency(-1), '-$0.0001');
assert.strictEqual(currency.satoshiToLocalCurrency(123), '$0.01'); assert.strictEqual(satoshiToLocalCurrency(123), '$0.01');
assert.strictEqual(currency.satoshiToLocalCurrency(156), '$0.02'); assert.strictEqual(satoshiToLocalCurrency(156), '$0.02');
assert.strictEqual(currency.satoshiToLocalCurrency(51), '$0.01'); assert.strictEqual(satoshiToLocalCurrency(51), '$0.01');
assert.strictEqual(currency.satoshiToLocalCurrency(45), '$0.0045'); assert.strictEqual(satoshiToLocalCurrency(45), '$0.0045');
assert.strictEqual(currency.satoshiToLocalCurrency(123456789), '$12,345.68'); assert.strictEqual(satoshiToLocalCurrency(123456789), '$12,345.68');
assert.strictEqual(currency.BTCToLocalCurrency(1), '$10,000.00'); assert.strictEqual(BTCToLocalCurrency(1), '$10,000.00');
assert.strictEqual(currency.BTCToLocalCurrency(-1), '-$10,000.00'); assert.strictEqual(BTCToLocalCurrency(-1), '-$10,000.00');
assert.strictEqual(currency.BTCToLocalCurrency(1.00000001), '$10,000.00'); assert.strictEqual(BTCToLocalCurrency(1.00000001), '$10,000.00');
assert.strictEqual(currency.BTCToLocalCurrency(1.0000123), '$10,000.12'); assert.strictEqual(BTCToLocalCurrency(1.0000123), '$10,000.12');
assert.strictEqual(currency.BTCToLocalCurrency(1.0000146), '$10,000.15'); assert.strictEqual(BTCToLocalCurrency(1.0000146), '$10,000.15');
assert.strictEqual(currency.satoshiToBTC(1), '0.00000001'); assert.strictEqual(satoshiToBTC(1), '0.00000001');
assert.strictEqual(currency.satoshiToBTC(-1), '-0.00000001'); assert.strictEqual(satoshiToBTC(-1), '-0.00000001');
assert.strictEqual(currency.satoshiToBTC(100000000), '1'); assert.strictEqual(satoshiToBTC(100000000), '1');
assert.strictEqual(currency.satoshiToBTC(123456789123456789), '1234567891.2345678'); // eslint-disable-line @typescript-eslint/no-loss-of-precision assert.strictEqual(satoshiToBTC(123456789123456789), '1234567891.2345678'); // eslint-disable-line @typescript-eslint/no-loss-of-precision
currency._setPreferredFiatCurrency(FiatUnit.JPY); _setPreferredFiatCurrency(FiatUnit.JPY);
currency._setExchangeRate('BTC_JPY', 1043740.8614); _setExchangeRate('BTC_JPY', 1043740.8614);
assert.ok( assert.ok(satoshiToLocalCurrency(1) === '¥0.01' || satoshiToLocalCurrency(1) === '¥0.01', 'Unexpected: ' + satoshiToLocalCurrency(1));
currency.satoshiToLocalCurrency(1) === '¥0.01' || currency.satoshiToLocalCurrency(1) === '¥0.01',
'Unexpected: ' + currency.satoshiToLocalCurrency(1),
);
}); });
}); });

View file

@ -2,7 +2,7 @@ import assert from 'assert';
import { BitcoinUnit } from '../../models/bitcoinUnits'; import { BitcoinUnit } from '../../models/bitcoinUnits';
import { FiatUnit } from '../../models/fiatUnit'; import { FiatUnit } from '../../models/fiatUnit';
import { _leaveNumbersAndDots, formatBalanceWithoutSuffix, formatBalancePlain, formatBalance } from '../../loc'; import { _leaveNumbersAndDots, formatBalanceWithoutSuffix, formatBalancePlain, formatBalance } from '../../loc';
const currency = require('../../blue_modules/currency'); import { _setExchangeRate, _setPreferredFiatCurrency, _setSkipUpdateExchangeRate } from '../../blue_modules/currency';
describe('Localization', () => { describe('Localization', () => {
it('internal formatter', () => { it('internal formatter', () => {
@ -12,8 +12,8 @@ describe('Localization', () => {
}); });
it('formatBalancePlain() && formatBalancePlain()', () => { it('formatBalancePlain() && formatBalancePlain()', () => {
currency._setExchangeRate('BTC_RUB', 660180.143); _setExchangeRate('BTC_RUB', 660180.143);
currency._setPreferredFiatCurrency(FiatUnit.RUB); _setPreferredFiatCurrency(FiatUnit.RUB);
let newInputValue = formatBalanceWithoutSuffix(152, BitcoinUnit.LOCAL_CURRENCY, false); let newInputValue = formatBalanceWithoutSuffix(152, BitcoinUnit.LOCAL_CURRENCY, false);
assert.ok(newInputValue === 'RUB 1.00' || newInputValue === '1,00 ₽', 'Unexpected: ' + newInputValue); assert.ok(newInputValue === 'RUB 1.00' || newInputValue === '1,00 ₽', 'Unexpected: ' + newInputValue);
newInputValue = formatBalancePlain(152, BitcoinUnit.LOCAL_CURRENCY, false); newInputValue = formatBalancePlain(152, BitcoinUnit.LOCAL_CURRENCY, false);
@ -32,8 +32,8 @@ describe('Localization', () => {
newInputValue = formatBalancePlain(76, BitcoinUnit.LOCAL_CURRENCY, false); newInputValue = formatBalancePlain(76, BitcoinUnit.LOCAL_CURRENCY, false);
assert.strictEqual(newInputValue, '0.50'); assert.strictEqual(newInputValue, '0.50');
currency._setExchangeRate('BTC_USD', 10000); _setExchangeRate('BTC_USD', 10000);
currency._setPreferredFiatCurrency(FiatUnit.USD); _setPreferredFiatCurrency(FiatUnit.USD);
newInputValue = formatBalanceWithoutSuffix(16793829, BitcoinUnit.LOCAL_CURRENCY, false); newInputValue = formatBalanceWithoutSuffix(16793829, BitcoinUnit.LOCAL_CURRENCY, false);
assert.strictEqual(newInputValue, '$1,679.38'); assert.strictEqual(newInputValue, '$1,679.38');
newInputValue = formatBalancePlain(16793829, BitcoinUnit.LOCAL_CURRENCY, false); newInputValue = formatBalancePlain(16793829, BitcoinUnit.LOCAL_CURRENCY, false);
@ -55,11 +55,11 @@ describe('Localization', () => {
])( ])(
'can formatBalanceWithoutSuffix', 'can formatBalanceWithoutSuffix',
async (balance, toUnit, withFormatting, expectedResult, shouldResetRate) => { async (balance, toUnit, withFormatting, expectedResult, shouldResetRate) => {
currency._setExchangeRate('BTC_USD', 1); _setExchangeRate('BTC_USD', 1);
currency._setPreferredFiatCurrency(FiatUnit.USD); _setPreferredFiatCurrency(FiatUnit.USD);
if (shouldResetRate) { if (shouldResetRate) {
currency._setExchangeRate('BTC_USD', false); _setExchangeRate('BTC_USD', false);
currency._setSkipUpdateExchangeRate(); _setSkipUpdateExchangeRate();
} }
const actualResult = formatBalanceWithoutSuffix(balance, toUnit, withFormatting); const actualResult = formatBalanceWithoutSuffix(balance, toUnit, withFormatting);
assert.strictEqual(actualResult, expectedResult); assert.strictEqual(actualResult, expectedResult);
@ -74,8 +74,8 @@ describe('Localization', () => {
])( ])(
'can formatBalance', 'can formatBalance',
async (balance, toUnit, withFormatting, expectedResult) => { async (balance, toUnit, withFormatting, expectedResult) => {
currency._setExchangeRate('BTC_USD', 1); _setExchangeRate('BTC_USD', 1);
currency._setPreferredFiatCurrency(FiatUnit.USD); _setPreferredFiatCurrency(FiatUnit.USD);
const actualResult = formatBalance(balance, toUnit, withFormatting); const actualResult = formatBalance(balance, toUnit, withFormatting);
assert.strictEqual(actualResult, expectedResult); assert.strictEqual(actualResult, expectedResult);
}, },