2024-04-18 03:05:48 +02:00
|
|
|
import React, { createContext, useContext, useEffect, useState } from 'react';
|
2024-04-15 22:53:44 +02:00
|
|
|
import { startAndDecrypt } from './start-and-decrypt';
|
2021-09-23 15:05:10 +02:00
|
|
|
import Notifications from '../blue_modules/notifications';
|
2024-04-15 22:53:44 +02:00
|
|
|
import { LegacyWallet, TTXMetadata, WatchOnlyWallet, BlueApp as BlueAppClass } from '../class';
|
2024-03-15 21:05:15 +01:00
|
|
|
import type { TWallet } from '../class/wallets/types';
|
2024-02-07 20:24:24 +01:00
|
|
|
import presentAlert from '../components/Alert';
|
2024-04-18 03:05:48 +02:00
|
|
|
import loc from '../loc';
|
2024-03-24 22:07:43 +01:00
|
|
|
import * as BlueElectrum from './BlueElectrum';
|
2024-03-15 21:05:15 +01:00
|
|
|
import triggerHapticFeedback, { HapticFeedbackTypes } from './hapticFeedback';
|
2024-03-31 21:59:14 +02:00
|
|
|
import A from '../blue_modules/analytics';
|
2024-03-15 21:05:15 +01:00
|
|
|
|
2024-04-15 22:53:44 +02:00
|
|
|
const BlueApp = BlueAppClass.getInstance();
|
|
|
|
|
2024-03-15 21:05:15 +01:00
|
|
|
// hashmap of timestamps we _started_ refetching some wallet
|
|
|
|
const _lastTimeTriedToRefetchWallet: { [walletID: string]: number } = {};
|
|
|
|
|
|
|
|
interface BlueStorageContextType {
|
|
|
|
wallets: TWallet[];
|
|
|
|
setWalletsWithNewOrder: (wallets: TWallet[]) => void;
|
|
|
|
txMetadata: TTXMetadata;
|
|
|
|
saveToDisk: (force?: boolean) => Promise<void>;
|
|
|
|
selectedWalletID: string | undefined;
|
|
|
|
setSelectedWalletID: (walletID: string | undefined) => void;
|
|
|
|
addWallet: (wallet: TWallet) => void;
|
|
|
|
deleteWallet: (wallet: TWallet) => void;
|
|
|
|
currentSharedCosigner: string;
|
|
|
|
setSharedCosigner: (cosigner: string) => void;
|
|
|
|
addAndSaveWallet: (wallet: TWallet) => Promise<void>;
|
|
|
|
fetchAndSaveWalletTransactions: (walletID: string) => Promise<void>;
|
|
|
|
walletsInitialized: boolean;
|
|
|
|
setWalletsInitialized: (initialized: boolean) => void;
|
|
|
|
refreshAllWalletTransactions: (lastSnappedTo?: number, showUpdateStatusIndicator?: boolean) => Promise<void>;
|
|
|
|
resetWallets: () => void;
|
|
|
|
walletTransactionUpdateStatus: WalletTransactionsStatus | string;
|
|
|
|
setWalletTransactionUpdateStatus: (status: WalletTransactionsStatus | string) => void;
|
|
|
|
isElectrumDisabled: boolean;
|
|
|
|
setIsElectrumDisabled: (value: boolean) => void;
|
|
|
|
reloadTransactionsMenuActionFunction: () => void;
|
|
|
|
setReloadTransactionsMenuActionFunction: (func: () => void) => void;
|
|
|
|
getTransactions: typeof BlueApp.getTransactions;
|
|
|
|
fetchWalletBalances: typeof BlueApp.fetchWalletBalances;
|
|
|
|
fetchWalletTransactions: typeof BlueApp.fetchWalletTransactions;
|
|
|
|
getBalance: typeof BlueApp.getBalance;
|
|
|
|
isStorageEncrypted: typeof BlueApp.storageIsEncrypted;
|
|
|
|
startAndDecrypt: typeof startAndDecrypt;
|
|
|
|
encryptStorage: typeof BlueApp.encryptStorage;
|
|
|
|
sleep: typeof BlueApp.sleep;
|
|
|
|
createFakeStorage: typeof BlueApp.createFakeStorage;
|
|
|
|
decryptStorage: typeof BlueApp.decryptStorage;
|
|
|
|
isPasswordInUse: typeof BlueApp.isPasswordInUse;
|
|
|
|
cachedPassword: typeof BlueApp.cachedPassword;
|
|
|
|
getItem: typeof BlueApp.getItem;
|
|
|
|
setItem: typeof BlueApp.setItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
export enum WalletTransactionsStatus {
|
|
|
|
NONE = 'NONE',
|
|
|
|
ALL = 'ALL',
|
|
|
|
}
|
|
|
|
// @ts-ignore defaut value does not match the type
|
|
|
|
export const BlueStorageContext = createContext<BlueStorageContextType>(undefined);
|
|
|
|
export const BlueStorageProvider = ({ children }: { children: React.ReactNode }) => {
|
|
|
|
const [wallets, setWallets] = useState<TWallet[]>([]);
|
|
|
|
const [selectedWalletID, setSelectedWalletID] = useState<undefined | string>();
|
|
|
|
const [walletTransactionUpdateStatus, setWalletTransactionUpdateStatus] = useState<WalletTransactionsStatus | string>(
|
|
|
|
WalletTransactionsStatus.NONE,
|
|
|
|
);
|
|
|
|
const [walletsInitialized, setWalletsInitialized] = useState<boolean>(false);
|
|
|
|
const [isElectrumDisabled, setIsElectrumDisabled] = useState<boolean>(true);
|
|
|
|
const [currentSharedCosigner, setCurrentSharedCosigner] = useState<string>('');
|
|
|
|
const [reloadTransactionsMenuActionFunction, setReloadTransactionsMenuActionFunction] = useState<() => void>(() => {});
|
2021-08-24 07:00:57 +02:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
BlueElectrum.isDisabled().then(setIsElectrumDisabled);
|
|
|
|
}, []);
|
2021-01-31 06:02:48 +01:00
|
|
|
|
2021-09-25 17:04:45 +02:00
|
|
|
useEffect(() => {
|
2024-03-10 23:37:02 +01:00
|
|
|
if (walletsInitialized) {
|
|
|
|
BlueElectrum.connectMain();
|
|
|
|
}
|
|
|
|
}, [walletsInitialized]);
|
|
|
|
|
2024-03-15 21:05:15 +01:00
|
|
|
const saveToDisk = async (force: boolean = false) => {
|
2021-09-07 21:30:07 +02:00
|
|
|
if (BlueApp.getWallets().length === 0 && !force) {
|
|
|
|
console.log('not saving empty wallets array');
|
|
|
|
return;
|
|
|
|
}
|
2020-10-24 19:20:59 +02:00
|
|
|
BlueApp.tx_metadata = txMetadata;
|
|
|
|
await BlueApp.saveToDisk();
|
|
|
|
setWallets([...BlueApp.getWallets()]);
|
|
|
|
txMetadata = BlueApp.tx_metadata;
|
|
|
|
};
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
setWallets(BlueApp.getWallets());
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const resetWallets = () => {
|
|
|
|
setWallets(BlueApp.getWallets());
|
|
|
|
};
|
|
|
|
|
2024-03-15 21:05:15 +01:00
|
|
|
const setWalletsWithNewOrder = (wlts: TWallet[]) => {
|
2023-07-25 15:50:04 +02:00
|
|
|
BlueApp.wallets = wlts;
|
2020-10-24 19:20:59 +02:00
|
|
|
saveToDisk();
|
|
|
|
};
|
|
|
|
|
2024-03-15 21:05:15 +01:00
|
|
|
const refreshAllWalletTransactions = async (lastSnappedTo?: number, showUpdateStatusIndicator: boolean = true) => {
|
2020-10-24 19:20:59 +02:00
|
|
|
let noErr = true;
|
|
|
|
try {
|
2024-01-20 23:16:36 +01:00
|
|
|
await BlueElectrum.waitTillConnected();
|
2021-01-28 01:30:42 +01:00
|
|
|
if (showUpdateStatusIndicator) {
|
|
|
|
setWalletTransactionUpdateStatus(WalletTransactionsStatus.ALL);
|
|
|
|
}
|
2022-12-12 03:34:50 +01:00
|
|
|
const paymentCodesStart = Date.now();
|
2024-03-15 21:05:15 +01:00
|
|
|
await BlueApp.fetchSenderPaymentCodes(lastSnappedTo);
|
2022-12-12 03:34:50 +01:00
|
|
|
const paymentCodesEnd = Date.now();
|
|
|
|
console.log('fetch payment codes took', (paymentCodesEnd - paymentCodesStart) / 1000, 'sec');
|
2020-10-24 19:20:59 +02:00
|
|
|
const balanceStart = +new Date();
|
2020-11-13 16:14:49 +01:00
|
|
|
await fetchWalletBalances(lastSnappedTo);
|
2020-10-24 19:20:59 +02:00
|
|
|
const balanceEnd = +new Date();
|
|
|
|
console.log('fetch balance took', (balanceEnd - balanceStart) / 1000, 'sec');
|
|
|
|
const start = +new Date();
|
2020-11-13 16:14:49 +01:00
|
|
|
await fetchWalletTransactions(lastSnappedTo);
|
2020-10-24 19:20:59 +02:00
|
|
|
const end = +new Date();
|
|
|
|
console.log('fetch tx took', (end - start) / 1000, 'sec');
|
|
|
|
} catch (err) {
|
|
|
|
noErr = false;
|
|
|
|
console.warn(err);
|
2021-01-28 01:30:42 +01:00
|
|
|
} finally {
|
|
|
|
setWalletTransactionUpdateStatus(WalletTransactionsStatus.NONE);
|
2020-10-24 19:20:59 +02:00
|
|
|
}
|
|
|
|
if (noErr) await saveToDisk(); // caching
|
|
|
|
};
|
|
|
|
|
2024-03-15 21:05:15 +01:00
|
|
|
const fetchAndSaveWalletTransactions = async (walletID: string) => {
|
2020-10-24 19:20:59 +02:00
|
|
|
const index = wallets.findIndex(wallet => wallet.getID() === walletID);
|
|
|
|
let noErr = true;
|
|
|
|
try {
|
2021-01-01 20:15:40 +01:00
|
|
|
// 5sec debounce:
|
|
|
|
if (+new Date() - _lastTimeTriedToRefetchWallet[walletID] < 5000) {
|
|
|
|
console.log('re-fetch wallet happens too fast; NOP');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_lastTimeTriedToRefetchWallet[walletID] = +new Date();
|
|
|
|
|
2020-10-24 19:20:59 +02:00
|
|
|
await BlueElectrum.waitTillConnected();
|
2024-01-20 23:16:36 +01:00
|
|
|
setWalletTransactionUpdateStatus(walletID);
|
2020-10-24 19:20:59 +02:00
|
|
|
const balanceStart = +new Date();
|
|
|
|
await fetchWalletBalances(index);
|
|
|
|
const balanceEnd = +new Date();
|
|
|
|
console.log('fetch balance took', (balanceEnd - balanceStart) / 1000, 'sec');
|
|
|
|
const start = +new Date();
|
|
|
|
await fetchWalletTransactions(index);
|
|
|
|
const end = +new Date();
|
|
|
|
console.log('fetch tx took', (end - start) / 1000, 'sec');
|
|
|
|
} catch (err) {
|
|
|
|
noErr = false;
|
|
|
|
console.warn(err);
|
2021-01-28 01:30:42 +01:00
|
|
|
} finally {
|
|
|
|
setWalletTransactionUpdateStatus(WalletTransactionsStatus.NONE);
|
2020-10-24 19:20:59 +02:00
|
|
|
}
|
|
|
|
if (noErr) await saveToDisk(); // caching
|
|
|
|
};
|
|
|
|
|
2024-03-15 21:05:15 +01:00
|
|
|
const addWallet = (wallet: TWallet) => {
|
2020-10-24 19:20:59 +02:00
|
|
|
BlueApp.wallets.push(wallet);
|
|
|
|
setWallets([...BlueApp.getWallets()]);
|
|
|
|
};
|
|
|
|
|
2024-03-15 21:05:15 +01:00
|
|
|
const deleteWallet = (wallet: TWallet) => {
|
2020-10-24 19:20:59 +02:00
|
|
|
BlueApp.deleteWallet(wallet);
|
|
|
|
setWallets([...BlueApp.getWallets()]);
|
|
|
|
};
|
|
|
|
|
2024-03-15 21:05:15 +01:00
|
|
|
const addAndSaveWallet = async (w: TWallet) => {
|
2021-09-23 15:05:10 +02:00
|
|
|
if (wallets.some(i => i.getID() === w.getID())) {
|
2023-12-29 12:52:12 +01:00
|
|
|
triggerHapticFeedback(HapticFeedbackTypes.NotificationError);
|
2024-02-07 20:24:24 +01:00
|
|
|
presentAlert({ message: 'This wallet has been previously imported.' });
|
2021-09-23 15:05:10 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
const emptyWalletLabel = new LegacyWallet().getLabel();
|
2023-12-29 12:52:12 +01:00
|
|
|
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
|
2021-09-23 15:05:10 +02:00
|
|
|
if (w.getLabel() === emptyWalletLabel) w.setLabel(loc.wallets.import_imported + ' ' + w.typeReadable);
|
|
|
|
w.setUserHasSavedExport(true);
|
|
|
|
addWallet(w);
|
|
|
|
await saveToDisk();
|
|
|
|
A(A.ENUM.CREATED_WALLET);
|
2024-04-26 04:02:22 +02:00
|
|
|
presentAlert({
|
|
|
|
hapticFeedback: HapticFeedbackTypes.ImpactHeavy,
|
|
|
|
message: w.type === WatchOnlyWallet.type ? loc.wallets.import_success_watchonly : loc.wallets.import_success,
|
|
|
|
});
|
2024-03-15 21:05:15 +01:00
|
|
|
// @ts-ignore need to type notifications first
|
2021-09-23 15:05:10 +02:00
|
|
|
Notifications.majorTomToGroundControl(w.getAllExternalAddresses(), [], []);
|
|
|
|
// start balance fetching at the background
|
|
|
|
await w.fetchBalance();
|
|
|
|
setWallets([...BlueApp.getWallets()]);
|
|
|
|
};
|
|
|
|
|
2024-03-15 21:05:15 +01:00
|
|
|
let txMetadata = BlueApp.tx_metadata;
|
2020-10-24 19:20:59 +02:00
|
|
|
const getTransactions = BlueApp.getTransactions;
|
|
|
|
const fetchWalletBalances = BlueApp.fetchWalletBalances;
|
|
|
|
const fetchWalletTransactions = BlueApp.fetchWalletTransactions;
|
|
|
|
const getBalance = BlueApp.getBalance;
|
|
|
|
const isStorageEncrypted = BlueApp.storageIsEncrypted;
|
|
|
|
const encryptStorage = BlueApp.encryptStorage;
|
|
|
|
const sleep = BlueApp.sleep;
|
|
|
|
const createFakeStorage = BlueApp.createFakeStorage;
|
|
|
|
const decryptStorage = BlueApp.decryptStorage;
|
|
|
|
const isPasswordInUse = BlueApp.isPasswordInUse;
|
|
|
|
const cachedPassword = BlueApp.cachedPassword;
|
2024-04-18 03:05:48 +02:00
|
|
|
|
2020-10-24 19:20:59 +02:00
|
|
|
const getItem = BlueApp.getItem;
|
|
|
|
const setItem = BlueApp.setItem;
|
|
|
|
|
2024-03-15 21:05:15 +01:00
|
|
|
const value: BlueStorageContextType = {
|
|
|
|
wallets,
|
|
|
|
setWalletsWithNewOrder,
|
|
|
|
txMetadata,
|
|
|
|
saveToDisk,
|
|
|
|
getTransactions,
|
|
|
|
selectedWalletID,
|
|
|
|
setSelectedWalletID,
|
|
|
|
addWallet,
|
|
|
|
deleteWallet,
|
|
|
|
currentSharedCosigner,
|
|
|
|
setSharedCosigner: setCurrentSharedCosigner,
|
|
|
|
addAndSaveWallet,
|
|
|
|
setItem,
|
|
|
|
getItem,
|
|
|
|
fetchWalletBalances,
|
|
|
|
fetchWalletTransactions,
|
|
|
|
fetchAndSaveWalletTransactions,
|
|
|
|
isStorageEncrypted,
|
|
|
|
encryptStorage,
|
|
|
|
startAndDecrypt,
|
|
|
|
cachedPassword,
|
|
|
|
getBalance,
|
|
|
|
walletsInitialized,
|
|
|
|
setWalletsInitialized,
|
|
|
|
refreshAllWalletTransactions,
|
|
|
|
sleep,
|
|
|
|
createFakeStorage,
|
|
|
|
resetWallets,
|
|
|
|
decryptStorage,
|
|
|
|
isPasswordInUse,
|
|
|
|
walletTransactionUpdateStatus,
|
|
|
|
setWalletTransactionUpdateStatus,
|
|
|
|
isElectrumDisabled,
|
|
|
|
setIsElectrumDisabled,
|
|
|
|
reloadTransactionsMenuActionFunction,
|
|
|
|
setReloadTransactionsMenuActionFunction,
|
|
|
|
};
|
|
|
|
|
|
|
|
return <BlueStorageContext.Provider value={value}>{children}</BlueStorageContext.Provider>;
|
2020-10-24 19:20:59 +02:00
|
|
|
};
|
2024-04-18 03:05:48 +02:00
|
|
|
|
|
|
|
export const useStorage = () => useContext(BlueStorageContext);
|