mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-01-19 05:45:15 +01:00
commit
42be5c9b56
71
App.js
71
App.js
@ -38,6 +38,7 @@ import Biometric from './class/biometrics';
|
||||
import WidgetCommunication from './blue_modules/WidgetCommunication';
|
||||
import changeNavigationBarColor from 'react-native-navigation-bar-color';
|
||||
const A = require('./blue_modules/analytics');
|
||||
const currency = require('./blue_modules/currency');
|
||||
|
||||
const eventEmitter = new NativeEventEmitter(NativeModules.EventEmitter);
|
||||
|
||||
@ -262,43 +263,43 @@ const App = () => {
|
||||
};
|
||||
|
||||
const handleAppStateChange = async nextAppState => {
|
||||
if (wallets.length > 0) {
|
||||
if ((appState.current.match(/background/) && nextAppState) === 'active' || nextAppState === undefined) {
|
||||
setTimeout(() => A(A.ENUM.APP_UNSUSPENDED), 2000);
|
||||
const processed = await processPushNotifications();
|
||||
if (processed) return;
|
||||
const clipboard = await BlueClipboard.getClipboardContent();
|
||||
const isAddressFromStoredWallet = wallets.some(wallet => {
|
||||
if (wallet.chain === Chain.ONCHAIN) {
|
||||
// checking address validity is faster than unwrapping hierarchy only to compare it to garbage
|
||||
return wallet.isAddressValid && wallet.isAddressValid(clipboard) && wallet.weOwnAddress(clipboard);
|
||||
} else {
|
||||
return wallet.isInvoiceGeneratedByWallet(clipboard) || wallet.weOwnAddress(clipboard);
|
||||
}
|
||||
});
|
||||
const isBitcoinAddress = DeeplinkSchemaMatch.isBitcoinAddress(clipboard);
|
||||
const isLightningInvoice = DeeplinkSchemaMatch.isLightningInvoice(clipboard);
|
||||
const isLNURL = DeeplinkSchemaMatch.isLnUrl(clipboard);
|
||||
const isBothBitcoinAndLightning = DeeplinkSchemaMatch.isBothBitcoinAndLightning(clipboard);
|
||||
if (
|
||||
!isAddressFromStoredWallet &&
|
||||
clipboardContent.current !== clipboard &&
|
||||
(isBitcoinAddress || isLightningInvoice || isLNURL || isBothBitcoinAndLightning)
|
||||
) {
|
||||
if (isBitcoinAddress) {
|
||||
setClipboardContentType(ClipboardContentType.BITCOIN);
|
||||
} else if (isLightningInvoice || isLNURL) {
|
||||
setClipboardContentType(ClipboardContentType.LIGHTNING);
|
||||
} else if (isBothBitcoinAndLightning) {
|
||||
setClipboardContentType(ClipboardContentType.BITCOIN);
|
||||
}
|
||||
setIsClipboardContentModalVisible(true);
|
||||
if (wallets.length === 0) return;
|
||||
if ((appState.current.match(/background/) && nextAppState === 'active') || nextAppState === undefined) {
|
||||
setTimeout(() => A(A.ENUM.APP_UNSUSPENDED), 2000);
|
||||
currency.updateExchangeRate();
|
||||
const processed = await processPushNotifications();
|
||||
if (processed) return;
|
||||
const clipboard = await BlueClipboard.getClipboardContent();
|
||||
const isAddressFromStoredWallet = wallets.some(wallet => {
|
||||
if (wallet.chain === Chain.ONCHAIN) {
|
||||
// checking address validity is faster than unwrapping hierarchy only to compare it to garbage
|
||||
return wallet.isAddressValid && wallet.isAddressValid(clipboard) && wallet.weOwnAddress(clipboard);
|
||||
} else {
|
||||
return wallet.isInvoiceGeneratedByWallet(clipboard) || wallet.weOwnAddress(clipboard);
|
||||
}
|
||||
clipboardContent.current = clipboard;
|
||||
}
|
||||
if (nextAppState) {
|
||||
appState.current = nextAppState;
|
||||
});
|
||||
const isBitcoinAddress = DeeplinkSchemaMatch.isBitcoinAddress(clipboard);
|
||||
const isLightningInvoice = DeeplinkSchemaMatch.isLightningInvoice(clipboard);
|
||||
const isLNURL = DeeplinkSchemaMatch.isLnUrl(clipboard);
|
||||
const isBothBitcoinAndLightning = DeeplinkSchemaMatch.isBothBitcoinAndLightning(clipboard);
|
||||
if (
|
||||
!isAddressFromStoredWallet &&
|
||||
clipboardContent.current !== clipboard &&
|
||||
(isBitcoinAddress || isLightningInvoice || isLNURL || isBothBitcoinAndLightning)
|
||||
) {
|
||||
if (isBitcoinAddress) {
|
||||
setClipboardContentType(ClipboardContentType.BITCOIN);
|
||||
} else if (isLightningInvoice || isLNURL) {
|
||||
setClipboardContentType(ClipboardContentType.LIGHTNING);
|
||||
} else if (isBothBitcoinAndLightning) {
|
||||
setClipboardContentType(ClipboardContentType.BITCOIN);
|
||||
}
|
||||
setIsClipboardContentModalVisible(true);
|
||||
}
|
||||
clipboardContent.current = clipboard;
|
||||
}
|
||||
if (nextAppState) {
|
||||
appState.current = nextAppState;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -69,6 +69,6 @@ const startAndDecrypt = async retry => {
|
||||
};
|
||||
|
||||
BlueApp.startAndDecrypt = startAndDecrypt;
|
||||
currency.startUpdater();
|
||||
currency.init();
|
||||
|
||||
module.exports = BlueApp;
|
||||
|
@ -5,15 +5,14 @@ import BigNumber from 'bignumber.js';
|
||||
import { FiatUnit, getFiatRate } from '../models/fiatUnit';
|
||||
import WidgetCommunication from './WidgetCommunication';
|
||||
|
||||
const PREFERRED_CURRENCY = 'preferredCurrency';
|
||||
const EXCHANGE_RATES = 'currency';
|
||||
const PREFERRED_CURRENCY_STORAGE_KEY = 'preferredCurrency';
|
||||
const EXCHANGE_RATES_STORAGE_KEY = 'currency';
|
||||
|
||||
let preferredFiatCurrency = FiatUnit.USD;
|
||||
const exchangeRates = {};
|
||||
let exchangeRates = {};
|
||||
let lastTimeUpdateExchangeRateWasCalled = 0;
|
||||
|
||||
const STRUCT = {
|
||||
LAST_UPDATED: 'LAST_UPDATED',
|
||||
};
|
||||
const LAST_UPDATED = 'LAST_UPDATED';
|
||||
|
||||
/**
|
||||
* Saves to storage preferred currency, whole object
|
||||
@ -23,7 +22,7 @@ const STRUCT = {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function setPrefferedCurrency(item) {
|
||||
await AsyncStorage.setItem(PREFERRED_CURRENCY, JSON.stringify(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('-', '_'));
|
||||
@ -31,21 +30,25 @@ async function setPrefferedCurrency(item) {
|
||||
}
|
||||
|
||||
async function getPreferredCurrency() {
|
||||
const preferredCurrency = await JSON.parse(await AsyncStorage.getItem(PREFERRED_CURRENCY));
|
||||
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 updateExchangeRate() {
|
||||
if (+new Date() - exchangeRates[STRUCT.LAST_UPDATED] <= 30 * 60 * 1000) {
|
||||
// not updating too often
|
||||
return;
|
||||
}
|
||||
|
||||
async function _restoreSavedExchangeRatesFromStorage() {
|
||||
try {
|
||||
preferredFiatCurrency = JSON.parse(await AsyncStorage.getItem(PREFERRED_CURRENCY));
|
||||
exchangeRates = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
|
||||
if (!exchangeRates) exchangeRates = {};
|
||||
} catch (_) {
|
||||
exchangeRates = {};
|
||||
}
|
||||
}
|
||||
|
||||
async function _restoreSavedPreferredFiatCurrencyFromStorage() {
|
||||
try {
|
||||
preferredFiatCurrency = JSON.parse(await AsyncStorage.getItem(PREFERRED_CURRENCY_STORAGE_KEY));
|
||||
if (preferredFiatCurrency === null) {
|
||||
throw Error('No Preferred Fiat selected');
|
||||
}
|
||||
@ -57,37 +60,66 @@ async function updateExchangeRate() {
|
||||
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 (+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);
|
||||
} catch (Err) {
|
||||
const lastSavedExchangeRate = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES));
|
||||
exchangeRates['BTC_' + preferredFiatCurrency.endPointKey] = lastSavedExchangeRate['BTC_' + preferredFiatCurrency.endPointKey] * 1;
|
||||
console.warn(Err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
exchangeRates[STRUCT.LAST_UPDATED] = +new Date();
|
||||
exchangeRates[LAST_UPDATED] = +new Date();
|
||||
exchangeRates['BTC_' + preferredFiatCurrency.endPointKey] = rate;
|
||||
await AsyncStorage.setItem(EXCHANGE_RATES, JSON.stringify(exchangeRates));
|
||||
await AsyncStorage.setItem(PREFERRED_CURRENCY, JSON.stringify(preferredFiatCurrency));
|
||||
await setPrefferedCurrency(preferredFiatCurrency);
|
||||
await AsyncStorage.setItem(EXCHANGE_RATES_STORAGE_KEY, JSON.stringify(exchangeRates));
|
||||
}
|
||||
|
||||
let interval = false;
|
||||
async function startUpdater() {
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
exchangeRates[STRUCT.LAST_UPDATED] = 0;
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
interval = setInterval(() => updateExchangeRate(), 2 * 60 * 100);
|
||||
return updateExchangeRate();
|
||||
}
|
||||
|
||||
function satoshiToLocalCurrency(satoshi) {
|
||||
if (!exchangeRates['BTC_' + preferredFiatCurrency.endPointKey]) {
|
||||
startUpdater();
|
||||
updateExchangeRate();
|
||||
return '...';
|
||||
}
|
||||
|
||||
@ -168,8 +200,7 @@ function _setExchangeRate(pair, rate) {
|
||||
}
|
||||
|
||||
module.exports.updateExchangeRate = updateExchangeRate;
|
||||
module.exports.startUpdater = startUpdater;
|
||||
module.exports.STRUCT = STRUCT;
|
||||
module.exports.init = init;
|
||||
module.exports.satoshiToLocalCurrency = satoshiToLocalCurrency;
|
||||
module.exports.fiatToBTC = fiatToBTC;
|
||||
module.exports.satoshiToBTC = satoshiToBTC;
|
||||
@ -180,5 +211,6 @@ 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.PREFERRED_CURRENCY = PREFERRED_CURRENCY;
|
||||
module.exports.EXCHANGE_RATES = EXCHANGE_RATES;
|
||||
module.exports.PREFERRED_CURRENCY = PREFERRED_CURRENCY_STORAGE_KEY;
|
||||
module.exports.EXCHANGE_RATES = EXCHANGE_RATES_STORAGE_KEY;
|
||||
module.exports.LAST_UPDATED = LAST_UPDATED;
|
||||
|
@ -1,4 +1,3 @@
|
||||
import Frisbee from 'frisbee';
|
||||
import untypedFiatUnit from './fiatUnits.json';
|
||||
|
||||
export const FiatUnitSource = {
|
||||
@ -10,13 +9,10 @@ export const FiatUnitSource = {
|
||||
|
||||
const RateExtractors = {
|
||||
CoinDesk: async (ticker: string): Promise<number> => {
|
||||
const api = new Frisbee({ baseURI: 'https://api.coindesk.com' });
|
||||
const res = await api.get(`/v1/bpi/currentprice/${ticker}.json`);
|
||||
if (res.err) throw new Error(`Could not update rate for ${ticker}: ${res.err}`);
|
||||
|
||||
let json;
|
||||
try {
|
||||
json = typeof res.body === 'string' ? JSON.parse(res.body) : res.body;
|
||||
const res = await fetch(`https://api.coindesk.com/v1/bpi/currentprice/${ticker}.json`);
|
||||
json = await res.json();
|
||||
} catch (e) {
|
||||
throw new Error(`Could not update rate for ${ticker}: ${e.message}`);
|
||||
}
|
||||
@ -27,14 +23,12 @@ const RateExtractors = {
|
||||
if (!(rate >= 0)) throw new Error(`Could not update rate for ${ticker}: data is wrong`);
|
||||
return rate;
|
||||
},
|
||||
Yadio: async (ticker: string): Promise<number> => {
|
||||
const api = new Frisbee({ baseURI: 'https://api.yadio.io/json' });
|
||||
const res = await api.get(`/${ticker}`);
|
||||
if (res.err) throw new Error(`Could not update rate for ${ticker}: ${res.err}`);
|
||||
|
||||
Yadio: async (ticker: string): Promise<number> => {
|
||||
let json;
|
||||
try {
|
||||
json = typeof res.body === 'string' ? JSON.parse(res.body) : res.body;
|
||||
const res = await fetch(`https://api.yadio.io/json/${ticker}`);
|
||||
json = await res.json();
|
||||
} catch (e) {
|
||||
throw new Error(`Could not update rate for ${ticker}: ${e.message}`);
|
||||
}
|
||||
@ -45,14 +39,12 @@ const RateExtractors = {
|
||||
if (!(rate >= 0)) throw new Error(`Could not update rate for ${ticker}: data is wrong`);
|
||||
return rate;
|
||||
},
|
||||
BitcoinduLiban: async (ticker: string): Promise<number> => {
|
||||
const api = new Frisbee({ baseURI: 'https://bitcoinduliban.org' });
|
||||
const res = await api.get('/api.php?key=lbpusd');
|
||||
if (res.err) throw new Error(`Could not update rate for ${ticker}: ${res.err}`);
|
||||
|
||||
BitcoinduLiban: async (ticker: string): Promise<number> => {
|
||||
let json;
|
||||
try {
|
||||
json = typeof res.body === 'string' ? JSON.parse(res.body) : res.body;
|
||||
const res = await fetch('https://bitcoinduliban.org/api.php?key=lbpusd');
|
||||
json = await res.json();
|
||||
} catch (e) {
|
||||
throw new Error(`Could not update rate for ${ticker}: ${e.message}`);
|
||||
}
|
||||
@ -63,14 +55,12 @@ const RateExtractors = {
|
||||
if (!(rate >= 0)) throw new Error(`Could not update rate for ${ticker}: data is wrong`);
|
||||
return rate;
|
||||
},
|
||||
Exir: async (ticker: string): Promise<number> => {
|
||||
const api = new Frisbee({ baseURI: 'https://api.exir.io' });
|
||||
const res = await api.get('/v1/ticker?symbol=btc-irt');
|
||||
if (res.err) throw new Error(`Could not update rate for ${ticker}: ${res.err}`);
|
||||
|
||||
Exir: async (ticker: string): Promise<number> => {
|
||||
let json;
|
||||
try {
|
||||
json = typeof res.body === 'string' ? JSON.parse(res.body) : res.body;
|
||||
const res = await fetch('https://api.exir.io/v1/ticker?symbol=btc-irt');
|
||||
json = await res.json();
|
||||
} catch (e) {
|
||||
throw new Error(`Could not update rate for ${ticker}: ${e.message}`);
|
||||
}
|
||||
|
43
package-lock.json
generated
43
package-lock.json
generated
@ -3390,6 +3390,11 @@
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz",
|
||||
"integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg=="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.2.tgz",
|
||||
"integrity": "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA=="
|
||||
},
|
||||
"shell-quote": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
|
||||
@ -6823,6 +6828,13 @@
|
||||
"integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==",
|
||||
"requires": {
|
||||
"node-fetch": "2.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"cross-spawn": {
|
||||
@ -15458,6 +15470,11 @@
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.2.tgz",
|
||||
"integrity": "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA=="
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||
@ -16268,9 +16285,10 @@
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.2.tgz",
|
||||
"integrity": "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA==",
|
||||
"dev": true
|
||||
},
|
||||
"node-int64": {
|
||||
"version": "0.4.0",
|
||||
@ -18283,6 +18301,13 @@
|
||||
"node-fetch": "^2.6.0",
|
||||
"open": "^6.2.0",
|
||||
"shell-quote": "1.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-fetch": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.2.tgz",
|
||||
"integrity": "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@react-native-community/cli-types": {
|
||||
@ -18614,6 +18639,11 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.1.0.tgz",
|
||||
"integrity": "sha512-Q89Z26KAfA3lpPGhbF6XMfYAm3jIV3avViy6KOJ2JLzFbeWHOvPQUu5aSJIWXap3gDZC2y1eF5HXEPI2wGqgvw=="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.2.tgz",
|
||||
"integrity": "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -18624,6 +18654,13 @@
|
||||
"requires": {
|
||||
"abort-controller": "^3.0.0",
|
||||
"node-fetch": "^2.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-fetch": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.2.tgz",
|
||||
"integrity": "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"recast": {
|
||||
|
@ -35,6 +35,7 @@
|
||||
"eslint-plugin-react": "^7.23.2",
|
||||
"eslint-plugin-standard": "^4.1.0",
|
||||
"jest": "^26.1.0",
|
||||
"node-fetch": "^2.6.2",
|
||||
"prettier": "^2.2.1",
|
||||
"react-test-renderer": "17.0.1",
|
||||
"typescript": "^4.3.5"
|
||||
|
@ -63,7 +63,7 @@ const Currency = () => {
|
||||
setIsSavingNewPreferredCurrency(true);
|
||||
setSelectedCurrency(item);
|
||||
await currency.setPrefferedCurrency(item);
|
||||
await currency.startUpdater();
|
||||
await currency.init(true);
|
||||
setIsSavingNewPreferredCurrency(false);
|
||||
setPreferredFiatCurrency();
|
||||
}}
|
||||
|
@ -250,7 +250,6 @@ const WalletTransactions = () => {
|
||||
return (
|
||||
<View style={styles.flex}>
|
||||
<View style={styles.listHeader}>
|
||||
|
||||
{/*
|
||||
Current logic - Onchain:
|
||||
- Shows buy button on middle when empty
|
||||
@ -265,7 +264,10 @@ const WalletTransactions = () => {
|
||||
The idea is to avoid showing on iOS an appstore/market style app that goes against the TOS.
|
||||
|
||||
*/}
|
||||
{wallet.getTransactions().length > 0 && wallet.chain !== Chain.OFFCHAIN && wallet.type !== LightningLdkWallet.type && renderSellFiat()}
|
||||
{wallet.getTransactions().length > 0 &&
|
||||
wallet.chain !== Chain.OFFCHAIN &&
|
||||
wallet.type !== LightningLdkWallet.type &&
|
||||
renderSellFiat()}
|
||||
{wallet.chain === Chain.OFFCHAIN && wallet.type !== LightningLdkWallet.type && renderMarketplaceButton()}
|
||||
{wallet.chain === Chain.OFFCHAIN && wallet.type !== LightningLdkWallet.type && Platform.OS === 'ios' && renderLappBrowserButton()}
|
||||
</View>
|
||||
|
@ -3,28 +3,26 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
|
||||
import { FiatUnit } from '../../models/fiatUnit';
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
describe('currency', () => {
|
||||
it('fetches exchange rate and saves to AsyncStorage', async () => {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 15000;
|
||||
const currency = require('../../blue_modules/currency');
|
||||
await currency.startUpdater();
|
||||
await currency.init();
|
||||
let cur = await AsyncStorage.getItem(currency.EXCHANGE_RATES);
|
||||
cur = JSON.parse(cur);
|
||||
assert.ok(Number.isInteger(cur[currency.STRUCT.LAST_UPDATED]));
|
||||
assert.ok(cur[currency.STRUCT.LAST_UPDATED] > 0);
|
||||
assert.ok(Number.isInteger(cur[currency.LAST_UPDATED]));
|
||||
assert.ok(cur[currency.LAST_UPDATED] > 0);
|
||||
assert.ok(cur.BTC_USD > 0);
|
||||
|
||||
// now, setting other currency as default
|
||||
await AsyncStorage.setItem(currency.PREFERRED_CURRENCY, JSON.stringify(FiatUnit.JPY));
|
||||
await currency.startUpdater();
|
||||
await currency.init(true);
|
||||
cur = JSON.parse(await AsyncStorage.getItem(currency.EXCHANGE_RATES));
|
||||
assert.ok(cur.BTC_JPY > 0);
|
||||
|
||||
// now setting with a proper setter
|
||||
await currency.setPrefferedCurrency(FiatUnit.EUR);
|
||||
await currency.startUpdater();
|
||||
await currency.init(true);
|
||||
const preferred = await currency.getPreferredCurrency();
|
||||
assert.strictEqual(preferred.endPointKey, 'EUR');
|
||||
cur = JSON.parse(await AsyncStorage.getItem(currency.EXCHANGE_RATES));
|
||||
@ -32,20 +30,20 @@ describe('currency', () => {
|
||||
|
||||
// test Yadio rate source
|
||||
await currency.setPrefferedCurrency(FiatUnit.ARS);
|
||||
await currency.startUpdater();
|
||||
await currency.init(true);
|
||||
cur = JSON.parse(await AsyncStorage.getItem(currency.EXCHANGE_RATES));
|
||||
assert.ok(cur.BTC_ARS > 0);
|
||||
|
||||
// test BitcoinduLiban rate source
|
||||
// disabled, because it throws "Service Temporarily Unavailable" on circleci
|
||||
// await currency.setPrefferedCurrency(FiatUnit.LBP);
|
||||
// await currency.startUpdater();
|
||||
// await currency.init(true);
|
||||
// cur = JSON.parse(await AsyncStorage.getItem(currency.EXCHANGE_RATES));
|
||||
// assert.ok(cur.BTC_LBP > 0);
|
||||
|
||||
// test Exir rate source
|
||||
await currency.setPrefferedCurrency(FiatUnit.IRR);
|
||||
await currency.startUpdater();
|
||||
await currency.init(true);
|
||||
cur = JSON.parse(await AsyncStorage.getItem(currency.EXCHANGE_RATES));
|
||||
assert.ok(cur.BTC_IRR > 0);
|
||||
});
|
||||
|
@ -4,6 +4,7 @@ import mockClipboard from '@react-native-clipboard/clipboard/jest/clipboard-mock
|
||||
|
||||
global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js
|
||||
global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js
|
||||
global.fetch = require('node-fetch');
|
||||
|
||||
jest.mock('@react-native-clipboard/clipboard', () => mockClipboard);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user