Merge branch 'master' into receiveview

This commit is contained in:
marcosrdz 2021-04-21 08:24:13 -04:00
commit e23bc398b8
10 changed files with 158 additions and 157 deletions

View file

@ -6,12 +6,12 @@ import {
useInstalled,
transferCurrentComplicationUserInfo,
} from 'react-native-watch-connectivity';
import { InteractionManager } from 'react-native';
import { Chain } from './models/bitcoinUnits';
import loc, { formatBalance, transactionTimeToReadable } from './loc';
import { BlueStorageContext } from './blue_modules/storage-context';
import Notifications from './blue_modules/notifications';
import { FiatUnit } from './models/fiatUnit';
import { MultisigHDWallet } from './class';
function WatchConnectivity() {
const { walletsInitialized, wallets, fetchWalletTransactions, saveToDisk, txMetadata, preferredFiatCurrency } = useContext(
@ -106,7 +106,7 @@ function WatchConnectivity() {
}
};
const sendWalletsToWatch = () => {
const sendWalletsToWatch = async () => {
if (!Array.isArray(wallets)) {
console.log('No Wallets set to sync with Watch app. Exiting...');
return;
@ -116,100 +116,102 @@ function WatchConnectivity() {
return;
}
return InteractionManager.runAfterInteractions(async () => {
const walletsToProcess = [];
const walletsToProcess = [];
for (const wallet of wallets) {
let receiveAddress;
if (wallet.getAddressAsync) {
if (wallet.chain === Chain.ONCHAIN) {
try {
receiveAddress = await wallet.getAddressAsync();
} catch (_) {}
if (!receiveAddress) {
// either sleep expired or getAddressAsync threw an exception
receiveAddress = wallet._getExternalAddressByIndex(wallet.next_free_address_index);
}
} else if (wallet.chain === Chain.OFFCHAIN) {
try {
await wallet.getAddressAsync();
receiveAddress = wallet.getAddress();
} catch (_) {}
if (!receiveAddress) {
// either sleep expired or getAddressAsync threw an exception
receiveAddress = wallet.getAddress();
}
for (const wallet of wallets) {
let receiveAddress;
if (wallet.getAddressAsync) {
if (wallet.chain === Chain.ONCHAIN) {
try {
receiveAddress = await wallet.getAddressAsync();
} catch (_) {}
if (!receiveAddress) {
// either sleep expired or getAddressAsync threw an exception
receiveAddress = wallet._getExternalAddressByIndex(wallet.next_free_address_index);
}
} else if (wallet.chain === Chain.OFFCHAIN) {
try {
await wallet.getAddressAsync();
receiveAddress = wallet.getAddress();
} catch (_) {}
if (!receiveAddress) {
// either sleep expired or getAddressAsync threw an exception
receiveAddress = wallet.getAddress();
}
}
const transactions = wallet.getTransactions(10);
const watchTransactions = [];
for (const transaction of transactions) {
let type = 'pendingConfirmation';
let memo = '';
let amount = 0;
}
const transactions = wallet.getTransactions(10);
const watchTransactions = [];
for (const transaction of transactions) {
let type = 'pendingConfirmation';
let memo = '';
let amount = 0;
if ('confirmations' in transaction && !(transaction.confirmations > 0)) {
if ('confirmations' in transaction && !(transaction.confirmations > 0)) {
type = 'pendingConfirmation';
} else if (transaction.type === 'user_invoice' || transaction.type === 'payment_request') {
const currentDate = new Date();
const now = (currentDate.getTime() / 1000) | 0;
const invoiceExpiration = transaction.timestamp + transaction.expire_time;
if (invoiceExpiration > now) {
type = 'pendingConfirmation';
} else if (transaction.type === 'user_invoice' || transaction.type === 'payment_request') {
const currentDate = new Date();
const now = (currentDate.getTime() / 1000) | 0;
const invoiceExpiration = transaction.timestamp + transaction.expire_time;
if (invoiceExpiration > now) {
type = 'pendingConfirmation';
} else if (invoiceExpiration < now) {
if (transaction.ispaid) {
type = 'received';
} else {
type = 'sent';
}
}
} else if (transaction.value / 100000000 < 0) {
type = 'sent';
} else {
type = 'received';
}
if (transaction.type === 'user_invoice' || transaction.type === 'payment_request') {
amount = isNaN(transaction.value) ? '0' : amount;
const currentDate = new Date();
const now = (currentDate.getTime() / 1000) | 0;
const invoiceExpiration = transaction.timestamp + transaction.expire_time;
if (invoiceExpiration > now) {
amount = formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString();
} else if (invoiceExpiration < now) {
if (transaction.ispaid) {
amount = formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString();
} else {
amount = loc.lnd.expired;
}
} else if (invoiceExpiration < now) {
if (transaction.ispaid) {
type = 'received';
} else {
type = 'sent';
}
}
} else if (transaction.value / 100000000 < 0) {
type = 'sent';
} else {
type = 'received';
}
if (transaction.type === 'user_invoice' || transaction.type === 'payment_request') {
amount = isNaN(transaction.value) ? '0' : amount;
const currentDate = new Date();
const now = (currentDate.getTime() / 1000) | 0;
const invoiceExpiration = transaction.timestamp + transaction.expire_time;
if (invoiceExpiration > now) {
amount = formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString();
} else if (invoiceExpiration < now) {
if (transaction.ispaid) {
amount = formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString();
} else {
amount = loc.lnd.expired;
}
} else {
amount = formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString();
}
if (txMetadata[transaction.hash] && txMetadata[transaction.hash].memo) {
memo = txMetadata[transaction.hash].memo;
} else if (transaction.memo) {
memo = transaction.memo;
}
const watchTX = { type, amount, memo, time: transactionTimeToReadable(transaction.received) };
watchTransactions.push(watchTX);
} else {
amount = formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString();
}
walletsToProcess.push({
label: wallet.getLabel(),
balance: formatBalance(Number(wallet.getBalance()), wallet.getPreferredBalanceUnit(), true),
type: wallet.type,
preferredBalanceUnit: wallet.getPreferredBalanceUnit(),
receiveAddress: receiveAddress,
transactions: watchTransactions,
xpub: wallet.getXpub() ? wallet.getXpub() : wallet.getSecret(),
hideBalance: wallet.hideBalance,
});
if (txMetadata[transaction.hash] && txMetadata[transaction.hash].memo) {
memo = txMetadata[transaction.hash].memo;
} else if (transaction.memo) {
memo = transaction.memo;
}
const watchTX = { type, amount, memo, time: transactionTimeToReadable(transaction.received) };
watchTransactions.push(watchTX);
}
updateApplicationContext({ wallets: walletsToProcess, randomID: Math.floor(Math.random() * 11) });
});
const walletInformation = {
label: wallet.getLabel(),
balance: formatBalance(Number(wallet.getBalance()), wallet.getPreferredBalanceUnit(), true),
type: wallet.type,
preferredBalanceUnit: wallet.getPreferredBalanceUnit(),
receiveAddress: receiveAddress,
transactions: watchTransactions,
hideBalance: wallet.hideBalance,
};
if (wallet.chain === Chain.ONCHAIN && wallet.type !== MultisigHDWallet.type) {
walletInformation.push({ xpub: wallet.getXpub() ? wallet.getXpub() : wallet.getSecret() });
}
walletsToProcess.push(walletInformation);
}
updateApplicationContext({ wallets: walletsToProcess, randomID: Math.floor(Math.random() * 11) });
};
return null;

View file

@ -37,6 +37,13 @@ export class AbstractWallet {
this._utxoMetadata = {};
}
/**
* @returns {number} Timestamp (millisecsec) of when last transactions were fetched from the network
*/
getLastTxFetch() {
return this._lastTxFetch;
}
getID() {
return createHash('sha256').update(this.getSecret()).digest().toString('hex');
}

View file

@ -16,6 +16,14 @@ export class WatchOnlyWallet extends LegacyWallet {
this.masterFingerprint = false;
}
/**
* @inheritDoc
*/
getLastTxFetch() {
if (this._hdWalletInstance) return this._hdWalletInstance.getLastTxFetch();
return super.getLastTxFetch();
}
allowSend() {
return this.useWithHardwareWalletEnabled() && this.isHd() && this._hdWalletInstance.allowSend();
}

View file

@ -271,8 +271,6 @@ PODS:
- React-Core
- react-native-safe-area-context (3.2.0):
- React-Core
- react-native-slider (3.0.3):
- React
- react-native-tcp-socket (3.7.1):
- CocoaAsyncSocket
- React
@ -384,7 +382,7 @@ PODS:
- RNSentry (2.4.0):
- React-Core
- Sentry (= 6.1.4)
- RNShare (5.1.6):
- RNShare (5.1.7):
- React-Core
- RNSVG (12.1.0):
- React
@ -453,7 +451,6 @@ DEPENDENCIES:
- react-native-is-catalyst (from `../node_modules/react-native-is-catalyst`)
- react-native-randombytes (from `../node_modules/react-native-randombytes`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- "react-native-slider (from `../node_modules/@react-native-community/slider`)"
- react-native-tcp-socket (from `../node_modules/react-native-tcp-socket`)
- react-native-webview (from `../node_modules/react-native-webview`)
- react-native-widget-center (from `../node_modules/react-native-widget-center`)
@ -572,8 +569,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-randombytes"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
react-native-slider:
:path: "../node_modules/@react-native-community/slider"
react-native-tcp-socket:
:path: "../node_modules/react-native-tcp-socket"
react-native-webview:
@ -705,7 +700,6 @@ SPEC CHECKSUMS:
react-native-is-catalyst: 52ee70e0123c82419dd4ce47dc4cc94b22467512
react-native-randombytes: 45ae693012df24c9a07a5e578b3b567c01468581
react-native-safe-area-context: e471852c5ed67eea4b10c5d9d43c1cebae3b231d
react-native-slider: b733e17fdd31186707146debf1f04b5d94aa1a93
react-native-tcp-socket: 96a4f104cdcc9c6621aafe92937f163d88447c5b
react-native-webview: 30f048378c6cee522ed9bbbedbc34acb21e58188
react-native-widget-center: 0f81d17beb163e7fb5848b06754d7d277fe7d99a
@ -740,7 +734,7 @@ SPEC CHECKSUMS:
RNScreens: f7ad633b2e0190b77b6a7aab7f914fad6f198d8d
RNSecureKeyStore: f1ad870e53806453039f650720d2845c678d89c8
RNSentry: b0d55027200c96f52e26b9bfb20296d47fc5051d
RNShare: 2db8b0346a4859f83d15528602ed5b6120a0452a
RNShare: 503c37af86611beadccba46156fcc42170c9fb42
RNSVG: ce9d996113475209013317e48b05c21ee988d42e
RNVectorIcons: bc69e6a278b14842063605de32bec61f0b251a59
RNWatch: e4c5d19506c94506860032fb68aedd5991beb985

View file

@ -136,12 +136,12 @@
"ask": "Have you saved your wallets backup phrase? This backup phrase is required to access your funds in case you lose this device. Without the backup phrase, your funds will be permanently lost.",
"ask_no": "No, I have not",
"ask_yes": "Yes, I have",
"ok": "OK, I wrote this down.",
"ok_lnd": "OK, I have saved it.",
"text": "Please take a moment to write down this mnemonic phrase on a piece of paper. Its your backup you can use to restore the wallet on another device.",
"ok": "OK, I wrote it down",
"ok_lnd": "OK, I have saved it",
"text": "Please take a moment to write down this mnemonic phrase on a piece of paper.\nIts your backup and you can use it to recover the wallet.",
"text_lnd": "Please save this wallet backup. It allows you to restore the wallet in case of loss.",
"text_lnd2": "This wallet is hosted by BlueWallet.",
"title": "Your wallet has been created."
"title": "Your wallet has been created"
},
"receive": {
"details_create": "Create",

5
package-lock.json generated
View file

@ -5812,11 +5812,6 @@
"invariant": "^2.2.4"
}
},
"@react-native-community/slider": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@react-native-community/slider/-/slider-3.0.3.tgz",
"integrity": "sha512-8IeHfDwJ9/CTUwFs6x90VlobV3BfuPgNLjTgC6dRZovfCWigaZwVNIFFJnHBakK3pW2xErAPwhdvNR4JeNoYbw=="
},
"@react-navigation/core": {
"version": "5.15.2",
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-5.15.2.tgz",

View file

@ -76,7 +76,6 @@
"@react-native-community/blur": "3.6.0",
"@react-native-community/masked-view": "0.1.10",
"@react-native-community/push-notification-ios": "1.8.0",
"@react-native-community/slider": "3.0.3",
"@react-navigation/drawer": "5.12.4",
"@react-navigation/native": "5.9.3",
"@react-navigation/stack": "5.14.3",

View file

@ -1,4 +1,4 @@
import React, { useCallback, useState, useContext } from 'react';
import React, { useCallback, useState, useContext, useRef, useEffect } from 'react';
import { ActivityIndicator, FlatList, StyleSheet, View, StatusBar } from 'react-native';
import { useFocusEffect, useNavigation, useRoute, useTheme } from '@react-navigation/native';
import Privacy from '../../blue_modules/Privacy';
@ -49,6 +49,8 @@ const WalletAddresses = () => {
const { walletID } = useRoute().params;
const addressList = useRef();
const wallet = wallets.find(w => w.getID() === walletID);
const balanceUnit = wallet.getPreferredBalanceUnit();
@ -65,6 +67,12 @@ const WalletAddresses = () => {
},
});
useEffect(() => {
if (showAddresses) {
addressList.current.scrollToIndex({ animated: false, index: 0 });
}
}, [showAddresses]);
const getAddresses = () => {
const addressList = [];
@ -108,30 +116,22 @@ const WalletAddresses = () => {
return <AddressItem {...item} balanceUnit={balanceUnit} onPress={() => navigateToReceive(item)} />;
};
const render = () => {
if (showAddresses) {
return (
<View style={stylesHook.root}>
<StatusBar barStyle="default" />
<FlatList
style={stylesHook.root}
data={addresses}
initialNumToRender={20}
contentInsetAdjustmentBehavior="automatic"
renderItem={renderRow}
/>
</View>
);
}
return (
<View style={[stylesHook.root, styles.loading]}>
<ActivityIndicator />
</View>
);
};
return render();
return (
<View style={[styles.root, stylesHook.root]}>
<StatusBar barStyle="default" />
<FlatList
contentContainerStyle={stylesHook.root}
ref={addressList}
data={addresses}
extraData={addresses}
initialNumToRender={40}
renderItem={renderRow}
ListEmptyComponent={<ActivityIndicator />}
centerContent={!showAddresses}
contentInsetAdjustmentBehavior="automatic"
/>
</View>
);
};
WalletAddresses.navigationOptions = navigationStyle({
@ -144,22 +144,4 @@ const styles = StyleSheet.create({
root: {
flex: 1,
},
loading: {
flex: 1,
justifyContent: 'center',
},
loadMoreButton: {
borderRadius: 9,
minHeight: 49,
paddingHorizontal: 8,
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row',
alignSelf: 'auto',
flexGrow: 1,
marginHorizontal: 16,
},
loadMoreText: {
fontSize: 16,
},
});

View file

@ -2,7 +2,7 @@ import React, { useEffect, useState, useCallback, useContext } from 'react';
import { ActivityIndicator, View, BackHandler, Text, ScrollView, StyleSheet, StatusBar, I18nManager } from 'react-native';
import { useNavigation, useRoute, useTheme } from '@react-navigation/native';
import { BlueSpacing20, SafeBlueArea, BlueText, BlueButton } from '../../BlueComponents';
import { SafeBlueArea, BlueButton } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import Privacy from '../../blue_modules/Privacy';
import loc from '../../loc';
@ -71,15 +71,15 @@ const PleaseBackup = () => {
</View>
) : (
<SafeBlueArea style={stylesHook.flex}>
<StatusBar barStyle="default" />
<ScrollView testID="PleaseBackupScrollView">
<StatusBar barStyle="light-content" />
<ScrollView contentContainerStyle={styles.flex} testID="PleaseBackupScrollView">
<View style={styles.please}>
<BlueText style={[styles.successText, stylesHook.successText]}>{loc.pleasebackup.success}</BlueText>
<BlueText style={[styles.pleaseText, stylesHook.pleaseText]}>{loc.pleasebackup.text}</BlueText>
<Text style={[styles.pleaseText, stylesHook.pleaseText]}>{loc.pleasebackup.text}</Text>
</View>
<View style={styles.list}>
<View style={styles.secret}>{renderSecret()}</View>
<BlueSpacing20 />
</View>
<View style={styles.bottom}>
<BlueButton testID="PleasebackupOk" onPress={handleBackButton} title={loc.pleasebackup.ok} />
</View>
</ScrollView>
@ -103,6 +103,10 @@ const styles = StyleSheet.create({
flex: 1,
justifyContent: 'center',
},
flex: {
flex: 1,
justifyContent: 'space-around',
},
word: {
marginRight: 8,
marginBottom: 8,
@ -115,19 +119,29 @@ const styles = StyleSheet.create({
wortText: {
fontWeight: 'bold',
textAlign: 'left',
fontSize: 17,
},
please: {
alignItems: 'center',
flexGrow: 1,
paddingHorizontal: 16,
},
list: {
flexGrow: 8,
paddingHorizontal: 16,
},
bottom: {
flexGrow: 2,
alignItems: 'center',
justifyContent: 'center',
},
successText: {
textAlign: 'center',
fontWeight: 'bold',
},
pleaseText: {
paddingBottom: 10,
paddingRight: 0,
paddingLeft: 0,
marginVertical: 16,
fontSize: 16,
fontWeight: '500',
},
secret: {
flexWrap: 'wrap',

View file

@ -149,7 +149,7 @@ const WalletTransactions = () => {
// refresh transactions if it never hasn't been done. It could be a fresh imported wallet
useEffect(() => {
if (wallet._lastTxFetch === 0) {
if (wallet.getLastTxFetch() === 0) {
refreshTransactions();
}
// eslint-disable-next-line react-hooks/exhaustive-deps