Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
gruve-p committed Sep 27, 2024
2 parents 0cc5adb + 1a5b8f8 commit b1fdce2
Show file tree
Hide file tree
Showing 20 changed files with 235 additions and 164 deletions.
3 changes: 2 additions & 1 deletion blue_modules/BlueElectrum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Realm from 'realm';
import { LegacyWallet, SegwitBech32Wallet, SegwitP2SHWallet, TaprootWallet } from '../class';
import presentAlert from '../components/Alert';
import loc from '../loc';
import { GROUP_IO_BLUEWALLET } from './currency';

const ElectrumClient = require('electrum-client');
const net = require('net');
Expand Down Expand Up @@ -226,7 +227,7 @@ export async function connectMain(): Promise<void> {
usingPeer = savedPeer;
}

await DefaultPreference.setName('group.org.groestlcoin.bluewallet123');
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
try {
if (usingPeer.host.endsWith('onion')) {
const randomPeer = getCurrentPeer();
Expand Down
3 changes: 2 additions & 1 deletion class/blue-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { SegwitP2SHWallet } from './wallets/segwit-p2sh-wallet';
import { SLIP39LegacyP2PKHWallet, SLIP39SegwitBech32Wallet, SLIP39SegwitP2SHWallet } from './wallets/slip39-wallets';
import { ExtendedTransaction, Transaction, TWallet } from './wallets/types';
import { WatchOnlyWallet } from './wallets/watch-only-wallet';
import { getLNDHub } from '../helpers/lndHub';

let usedBucketNum: boolean | number = false;
let savingInProgress = 0; // its both a flag and a counter of attempts to write to disk
Expand Down Expand Up @@ -437,7 +438,7 @@ export class BlueApp {
unserializedWallet = LightningCustodianWallet.fromJson(key) as unknown as LightningCustodianWallet;
let lndhub: false | any = false;
try {
lndhub = await AsyncStorage.getItem(BlueApp.LNDHUB);
lndhub = await getLNDHub();
} catch (error) {
console.warn(error);
}
Expand Down
8 changes: 6 additions & 2 deletions class/wallets/lightning-custodian-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -579,14 +579,17 @@ export class LightningCustodianWallet extends LegacyWallet {
}
}

static async isValidNodeAddress(address: string) {
const response = await fetch((address?.endsWith('/') ? address.slice(0, -1) : address) + '/getinfo', {
static async isValidNodeAddress(address: string): Promise<boolean> {
const normalizedAddress = new URL('/getinfo', address.replace(/([^:]\/)\/+/g, '$1'));

const response = await fetch(normalizedAddress.toString(), {
method: 'GET',
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json',
},
});

const json = await response.json();
if (!json) {
throw new Error('API failure: ' + response.statusText);
Expand All @@ -595,6 +598,7 @@ export class LightningCustodianWallet extends LegacyWallet {
if (json.code && json.code !== 1) {
throw new Error('API error: ' + json.message + ' (code ' + json.code + ')');
}

return true;
}

Expand Down
3 changes: 1 addition & 2 deletions components/Alert.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Alert as RNAlert, Platform, ToastAndroid } from 'react-native';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../blue_modules/hapticFeedback';
import loc from '../loc';

export enum AlertType {
Alert,
Expand Down Expand Up @@ -29,7 +28,7 @@ const presentAlert = ({
ToastAndroid.show(message, ToastAndroid.LONG);
break;
default:
RNAlert.alert(title ?? loc.alert.default, message);
RNAlert.alert(title ?? message, title && message ? message : undefined);
break;
}
};
Expand Down
29 changes: 19 additions & 10 deletions components/PromptPasswordConfirmationModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, useRef, forwardRef, useImperativeHandle, useEffect } from 'react';
import { View, Text, TextInput, StyleSheet, Animated, Easing, ViewStyle, Keyboard, Platform, UIManager } from 'react-native';
import { View, Text, TextInput, StyleSheet, Animated, Easing, ViewStyle, Keyboard, Platform, UIManager, ScrollView } from 'react-native';
import BottomModal, { BottomModalHandle } from './BottomModal';
import { useTheme } from '../components/themes';
import loc from '../loc';
Expand Down Expand Up @@ -46,6 +46,7 @@ const PromptPasswordConfirmationModal = forwardRef<PromptPasswordConfirmationMod
const { colors } = useTheme();
const passwordInputRef = useRef<TextInput>(null);
const confirmPasswordInputRef = useRef<TextInput>(null);
const scrollView = useRef<ScrollView>(null);

const stylesHook = StyleSheet.create({
modalContent: {
Expand Down Expand Up @@ -260,8 +261,11 @@ const PromptPasswordConfirmationModal = forwardRef<PromptPasswordConfirmationMod
ref={modalRef}
onDismiss={onModalDismiss}
grabber={false}
showCloseButton={!isSuccess}
onCloseModalPressed={handleCancel}
backgroundColor={colors.modal}
scrollRef={scrollView}
dismissible={false}
footer={
!isSuccess ? (
showExplanation && modalType === MODAL_TYPES.CREATE_PASSWORD ? (
Expand Down Expand Up @@ -294,19 +298,21 @@ const PromptPasswordConfirmationModal = forwardRef<PromptPasswordConfirmationMod
{modalType === MODAL_TYPES.CREATE_PASSWORD && showExplanation && (
<Animated.View style={{ opacity: explanationOpacity }}>
<Text style={[styles.textLabel, stylesHook.feeModalLabel]}>{loc.settings.encrypt_storage_explanation_headline}</Text>
<Text style={[styles.description, stylesHook.feeModalCustomText]}>
{loc.settings.encrypt_storage_explanation_description_line1}
</Text>
<Text style={[styles.description, stylesHook.feeModalCustomText]}>
{loc.settings.encrypt_storage_explanation_description_line2}
</Text>
<Animated.ScrollView style={styles.explanationScrollView} ref={scrollView}>
<Text style={[styles.description, stylesHook.feeModalCustomText]}>
{loc.settings.encrypt_storage_explanation_description_line1}
</Text>
<Text style={[styles.description, stylesHook.feeModalCustomText]}>
{loc.settings.encrypt_storage_explanation_description_line2}
</Text>
</Animated.ScrollView>
<View style={styles.feeModalFooter} />
</Animated.View>
)}
{(modalType === MODAL_TYPES.ENTER_PASSWORD ||
((modalType === MODAL_TYPES.CREATE_PASSWORD || modalType === MODAL_TYPES.CREATE_FAKE_STORAGE) && !showExplanation)) && (
<>
<Text style={[styles.textLabel, stylesHook.feeModalLabel]}>
<Text adjustsFontSizeToFit style={[styles.textLabel, stylesHook.feeModalLabel]}>
{modalType === MODAL_TYPES.CREATE_PASSWORD
? loc.settings.password_explain
: modalType === MODAL_TYPES.CREATE_FAKE_STORAGE
Expand Down Expand Up @@ -393,13 +399,13 @@ const styles = StyleSheet.create({
alignItems: 'center',
},
minHeight: {
minHeight: 350,
minHeight: 260,
},
feeModalFooter: {
paddingHorizontal: 16,
},
feeModalFooterSpacing: {
paddingHorizontal: 24,
paddingHorizontal: 16,
},
inputContainer: {
marginBottom: 10,
Expand Down Expand Up @@ -440,4 +446,7 @@ const styles = StyleSheet.create({
color: 'white',
fontSize: 30,
},
explanationScrollView: {
maxHeight: 200,
},
});
3 changes: 2 additions & 1 deletion components/TotalWalletsBalance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ const TotalWalletsBalance: React.FC = () => {

const formattedBalance = useMemo(
() => formatBalanceWithoutSuffix(Number(totalBalance), totalBalancePreferredUnit, true),
[totalBalance, totalBalancePreferredUnit],
// eslint-disable-next-line react-hooks/exhaustive-deps
[totalBalance, totalBalancePreferredUnit, preferredFiatCurrency],
);

const toolTipActions = useMemo(() => {
Expand Down
2 changes: 1 addition & 1 deletion components/TransactionListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { CommonToolTipActions } from '../typings/CommonToolTipActions';
import { pop } from '../NavigationService';

interface TransactionListItemProps {
itemPriceUnit: BitcoinUnit;
itemPriceUnit?: BitcoinUnit;
walletID: string;
item: Transaction & LightningTransaction; // using type intersection to have less issues with ts
searchQuery?: string;
Expand Down
40 changes: 14 additions & 26 deletions components/TransactionsNavigationHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import Clipboard from '@react-native-clipboard/clipboard';
import { I18nManager, Image, LayoutAnimation, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
Expand All @@ -10,12 +10,12 @@ import { BitcoinUnit } from '../models/bitcoinUnits';
import { FiatUnit } from '../models/fiatUnit';
import { BlurredBalanceView } from './BlurredBalanceView';
import { useSettings } from '../hooks/context/useSettings';
import { ToolTipMenuProps } from './types';
import ToolTipMenu from './TooltipMenu';

interface TransactionsNavigationHeaderProps {
wallet: TWallet;
onWalletUnitChange?: (wallet: any) => void;
unit: BitcoinUnit;
onWalletUnitChange: (unit: BitcoinUnit) => void;
onManageFundsPressed?: (id?: string) => void;
onWalletBalanceVisibilityChange?: (isShouldBeVisible: boolean) => void;
}
Expand All @@ -25,13 +25,12 @@ const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps>
onWalletUnitChange,
onManageFundsPressed,
onWalletBalanceVisibilityChange,
unit = BitcoinUnit.BTC,
}) => {
const [wallet, setWallet] = useState(initialWallet);
const [allowOnchainAddress, setAllowOnchainAddress] = useState(false);
const { preferredFiatCurrency } = useSettings();

const menuRef = useRef<ToolTipMenuProps>(null);

const verifyIfWalletAllowsOnchainAddress = useCallback(() => {
if (wallet.type === LightningCustodianWallet.type) {
wallet
Expand All @@ -55,25 +54,18 @@ const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps>
}, [wallet, verifyIfWalletAllowsOnchainAddress]);

const handleCopyPress = useCallback(() => {
const value = formatBalance(wallet.getBalance(), wallet.getPreferredBalanceUnit());
const value = formatBalance(wallet.getBalance(), unit);
if (value) {
Clipboard.setString(value);
}
}, [wallet]);
}, [unit, wallet]);

const handleBalanceVisibility = useCallback(() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
onWalletBalanceVisibilityChange?.(!wallet.hideBalance);
}, [onWalletBalanceVisibilityChange, wallet.hideBalance]);

const updateWalletWithNewUnit = (w: TWallet, newPreferredUnit: BitcoinUnit) => {
w.preferredBalanceUnit = newPreferredUnit;
return w;
};

const changeWalletBalanceUnit = () => {
if (menuRef.current?.dismissMenu) {
menuRef.current.dismissMenu();
}
let newWalletPreferredUnit = wallet.getPreferredBalanceUnit();

if (newWalletPreferredUnit === BitcoinUnit.BTC) {
Expand All @@ -84,10 +76,8 @@ const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps>
newWalletPreferredUnit = BitcoinUnit.BTC;
}

const updatedWallet = updateWalletWithNewUnit(wallet, newWalletPreferredUnit);
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setWallet(updatedWallet);
onWalletUnitChange?.(updatedWallet);
onWalletUnitChange(newWalletPreferredUnit);
};

const handleManageFundsPressed = useCallback(
Expand Down Expand Up @@ -126,14 +116,14 @@ const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps>
}, []);

const balance = useMemo(() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
const hideBalance = wallet.hideBalance;
const balanceUnit = wallet.getPreferredBalanceUnit();
const balanceFormatted =
balanceUnit === BitcoinUnit.LOCAL_CURRENCY
? formatBalance(wallet.getBalance(), balanceUnit, true)
: formatBalanceWithoutSuffix(wallet.getBalance(), balanceUnit, true);
unit === BitcoinUnit.LOCAL_CURRENCY
? formatBalance(wallet.getBalance(), unit, true)
: formatBalanceWithoutSuffix(wallet.getBalance(), unit, true);
return !hideBalance && balanceFormatted;
}, [wallet]);
}, [unit, wallet]);

const toolTipWalletBalanceActions = useMemo(() => {
return wallet.hideBalance
Expand Down Expand Up @@ -217,9 +207,7 @@ const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps>
</ToolTipMenu>
<TouchableOpacity style={styles.walletPreferredUnitView} onPress={changeWalletBalanceUnit}>
<Text style={styles.walletPreferredUnitText}>
{wallet.getPreferredBalanceUnit() === BitcoinUnit.LOCAL_CURRENCY
? (preferredFiatCurrency?.endPointKey ?? FiatUnit.USD)
: wallet.getPreferredBalanceUnit()}
{unit === BitcoinUnit.LOCAL_CURRENCY ? (preferredFiatCurrency?.endPointKey ?? FiatUnit.USD) : unit}
</Text>
</TouchableOpacity>
</View>
Expand Down
49 changes: 49 additions & 0 deletions helpers/lndHub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import DefaultPreference from 'react-native-default-preference';
import { BlueApp } from '../class';
import { GROUP_IO_BLUEWALLET } from '../blue_modules/currency';

// Function to get the value from DefaultPreference first, then fallback to AsyncStorage
// as DefaultPreference uses truly native storage.
// If found in AsyncStorage, migrate it to DefaultPreference and remove it from AsyncStorage.
export const getLNDHub = async (): Promise<string | undefined> => {
try {
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
let value = await DefaultPreference.get(BlueApp.LNDHUB);

// If not found, check AsyncStorage and migrate it to DefaultPreference
if (!value) {
value = await AsyncStorage.getItem(BlueApp.LNDHUB);

if (value) {
await DefaultPreference.set(BlueApp.LNDHUB, value);
await AsyncStorage.removeItem(BlueApp.LNDHUB);
console.log('Migrated LNDHub value from AsyncStorage to DefaultPreference');
}
}

return value ?? undefined;
} catch (error) {
console.error('Error getting LNDHub preference:', (error as Error).message);
return undefined;
}
};

export const setLNDHub = async (value: string): Promise<void> => {
try {
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
await DefaultPreference.set(BlueApp.LNDHUB, value);
} catch (error) {
console.error('Error setting LNDHub preference:', error);
}
};

export const clearLNDHub = async (): Promise<void> => {
try {
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
await DefaultPreference.clear(BlueApp.LNDHUB);
await AsyncStorage.removeItem(BlueApp.LNDHUB);
} catch (error) {
console.error('Error clearing LNDHub preference:', error);
}
};
Loading

0 comments on commit b1fdce2

Please sign in to comment.