From 6975534a4d58697280be9f77cfa31a19ffe41c2c Mon Sep 17 00:00:00 2001 From: Daniel Gonzalez Date: Tue, 28 Jan 2025 19:38:44 -0400 Subject: [PATCH] feat(wallet): Ported Wallet View --- package-lock.json | 89 ++++++++- package.json | 5 + src/App.js | 16 +- .../app-body/bch-wallet/clear-wallet.js | 59 ++++++ .../app-body/bch-wallet/copy-on-click.js | 55 ++++++ .../app-body/bch-wallet/import-wallet.js | 118 ++++++++++++ src/components/app-body/bch-wallet/index.js | 47 +++++ .../app-body/bch-wallet/optimize-wallet.js | 113 ++++++++++++ .../app-body/bch-wallet/wallet-summary.css | 4 + .../app-body/bch-wallet/wallet-summary.js | 165 +++++++++++++++++ src/components/app-body/bch-wallet/warning.js | 49 +++++ src/components/app-body/index.js | 7 +- src/components/nav-menu/index.js | 7 + src/hooks/state.js | 71 ++++++- src/services/async-load.js | 174 ++++++++++++++---- src/util/index.js | 24 +++ 16 files changed, 957 insertions(+), 46 deletions(-) create mode 100644 src/components/app-body/bch-wallet/clear-wallet.js create mode 100644 src/components/app-body/bch-wallet/copy-on-click.js create mode 100644 src/components/app-body/bch-wallet/import-wallet.js create mode 100644 src/components/app-body/bch-wallet/index.js create mode 100644 src/components/app-body/bch-wallet/optimize-wallet.js create mode 100644 src/components/app-body/bch-wallet/wallet-summary.css create mode 100644 src/components/app-body/bch-wallet/wallet-summary.js create mode 100644 src/components/app-body/bch-wallet/warning.js diff --git a/package-lock.json b/package-lock.json index 66e2247..9849b2f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,17 @@ { - "name": "react-bootstrap-web3-spa", - "version": "2.0.1", + "name": "bch-wallet-web3-spa", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "react-bootstrap-web3-spa", - "version": "2.0.1", + "name": "bch-wallet-web3-spa", + "version": "1.0.0", "dependencies": { + "@fortawesome/fontawesome-svg-core": "6.7.2", + "@fortawesome/free-regular-svg-icons": "6.7.2", + "@fortawesome/free-solid-svg-icons": "6.7.2", + "@fortawesome/react-fontawesome": "0.2.2", "axios": "0.27.2", "bch-message-lib": "2.2.1", "bootstrap": "5.2.0", @@ -16,6 +20,7 @@ "react-bootstrap": "2.10.7", "react-dom": "19.0.0", "react-scripts": "5.0.1", + "use-local-storage-state": "19.5.0", "use-query-params": "1.2.3" }, "devDependencies": { @@ -2057,6 +2062,64 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz", + "integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz", + "integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==", + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-regular-svg-icons": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.7.2.tgz", + "integrity": "sha512-7Z/ur0gvCMW8G93dXIQOkQqHo2M5HLhYrRVC0//fakJXxcF1VmMPsxnG6Ee8qEylA8b8Q3peQXWMNZ62lYF28g==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.2.tgz", + "integrity": "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz", + "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.9.5", "license": "Apache-2.0", @@ -12792,6 +12855,8 @@ "node_modules/node-fetch": { "name": "@achingbrain/node-fetch", "version": "2.6.7", + "resolved": "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-iTASGs+HTFK5E4ZqcMsHmeJ4zodyq8L38lZV33jwqcBJYoUt3HjN4+ot+O9/0b+ke8ddE7UgOtVuZN/OkV19/g==", "dev": true, "license": "MIT", "engines": { @@ -17340,6 +17405,22 @@ "requires-port": "^1.0.0" } }, + "node_modules/use-local-storage-state": { + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/use-local-storage-state/-/use-local-storage-state-19.5.0.tgz", + "integrity": "sha512-sUJAyFvsmqMpBhdwaRr7GTKkkoxb6PWeNVvpBDrLuwQF1PpbJRKIbOYeLLeqJI7B3wdfFlLLCBbmOdopiSTBOw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/astoilkov" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/use-query-params": { "version": "1.2.3", "license": "ISC", diff --git a/package.json b/package.json index c004c89..56646ce 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,10 @@ "name": "bch-wallet-web3-spa", "version": "1.0.0", "dependencies": { + "@fortawesome/fontawesome-svg-core": "6.7.2", + "@fortawesome/free-regular-svg-icons": "6.7.2", + "@fortawesome/free-solid-svg-icons": "6.7.2", + "@fortawesome/react-fontawesome": "0.2.2", "axios": "0.27.2", "bch-message-lib": "2.2.1", "bootstrap": "5.2.0", @@ -10,6 +14,7 @@ "react-bootstrap": "2.10.7", "react-dom": "19.0.0", "react-scripts": "5.0.1", + "use-local-storage-state": "19.5.0", "use-query-params": "1.2.3" }, "scripts": { diff --git a/src/App.js b/src/App.js index a819a3d..7e906b5 100644 --- a/src/App.js +++ b/src/App.js @@ -30,6 +30,7 @@ function App (props) { return prevBody }) }, []) + /** Load all required data before component start. */ useEffect(() => { async function asyncEffect () { @@ -55,8 +56,21 @@ function App (props) { addToModal('Initializing wallet', appData) console.log(`Initializing wallet with back end server ${appData.serverUrl}`) - const walletTemp = await asyncLoad.initWallet(appData.serverUrl) + const walletTemp = await asyncLoad.initWallet(appData.serverUrl, appData.lsState.mnemonic, appData) appData.setWallet(walletTemp) + // appData.updateBchWalletState({ walletObj: walletTemp.walletInfo, appData }) + + // Get the BCH balance of the wallet. + addToModal('Getting BCH balance', appData) + await asyncLoad.getWalletBchBalance(walletTemp, appData.updateBchWalletState, appData) + + // Get the SLP tokens held by the wallet. + addToModal('Getting SLP tokens', appData) + await asyncLoad.getSlpTokenBalances(walletTemp, appData.updateBchWalletState, appData) + + // Get the BCH spot price + addToModal('Getting BCH spot price in USD', appData) + await asyncLoad.getUSDExchangeRate(walletTemp, appData.updateBchWalletState, appData) // Update state appData.setShowStartModal(false) diff --git a/src/components/app-body/bch-wallet/clear-wallet.js b/src/components/app-body/bch-wallet/clear-wallet.js new file mode 100644 index 0000000..1213a5b --- /dev/null +++ b/src/components/app-body/bch-wallet/clear-wallet.js @@ -0,0 +1,59 @@ +/* +This Card component is used to clear the Local Storage and reset the wallet. +*/ + +// Global npm libraries +import React from 'react' +import { Container, Row, Col, Card, Button } from 'react-bootstrap' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faTriangleExclamation } from '@fortawesome/free-solid-svg-icons' + +const WalletClear = (props) => { + const { removeLocalStorageItem } = props.appData + + // Delete wallet data from Local Storage and reload the app. + const handleClearLocalStorage = () => { + console.log('Deleting wallet and reloading page.') + // Delete the mnemonic from Local Storage + removeLocalStorageItem('mnemonic') + // Reload the app. + window.location.reload() + } + + return ( + <> + + + + + + +

+ {' '} + Clear Local Storage +

+
+ + + Clicking the button below will clear the Local Storage, which + will reload the app with a newly created wallet. +
+ + Be sure to write down your 12-word mnemonic to back + up your wallet before clicking the button! + . +

+ +
+
+
+ +
+
+ + ) +} + +export default WalletClear diff --git a/src/components/app-body/bch-wallet/copy-on-click.js b/src/components/app-body/bch-wallet/copy-on-click.js new file mode 100644 index 0000000..fddb2c6 --- /dev/null +++ b/src/components/app-body/bch-wallet/copy-on-click.js @@ -0,0 +1,55 @@ +/* + This component is visually represented with a copy icon. A wallet property + is passed as a prop. When clicked, the wallet property is copied to the + system clipboard. +*/ + +// Global npm libraries +import React, { useCallback, useState } from 'react' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faCopy } from '@fortawesome/free-solid-svg-icons' + +const CopyOnClick = (props) => { + // State + const [iconVis, setIconVis] = useState(true) + // Props + const { appData, walletProp, value } = props + // App Util + const { appUtil } = appData + + // Function to copy the value to the clipboard. + const handleCopyToClipboard = useCallback(async (event) => { + appUtil.copyToClipboard(value) + + // hide icon in order to show the copied message + setIconVis(false) + + // restart icon visibility after 1 second + setTimeout(function () { + setIconVis(true) + }, 1000) + }, [value, appUtil]) + + return ( + <> + {iconVis && ( + handleCopyToClipboard(e)} + style={{ cursor: 'pointer' }} + /> + )} + {!iconVis && ( + + Copied! + + )} + + ) +} + +export default CopyOnClick diff --git a/src/components/app-body/bch-wallet/import-wallet.js b/src/components/app-body/bch-wallet/import-wallet.js new file mode 100644 index 0000000..726d4e4 --- /dev/null +++ b/src/components/app-body/bch-wallet/import-wallet.js @@ -0,0 +1,118 @@ +/* + This component allows the user to import a new wallet using a 12-word mnemonic. +*/ + +// Global npm libraries +import React, { useCallback } from 'react' +import { Container, Row, Col, Card, Button, Form } from 'react-bootstrap' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faFileExport, faPaste } from '@fortawesome/free-solid-svg-icons' +// import { Clipboard } from '@capacitor/clipboard' + +const WalletImport = (props) => { + const [newMnemonic, setNewMnemonic] = React.useState('') + const { appData } = props + + // Load mnemonic from clipboard + const pasteFromClipboard = async () => { + try { + const mnemonic = await appData.appUtil.readFromClipboard() + setNewMnemonic(mnemonic) + } catch (err) { + console.warn('Error pasting from clipboard: ', err) + } + } + + // Handle input change for mnemonic + const handleImportMnemonic = async (event) => { + const inputStr = event.target.value + const formattedInput = inputStr.toLowerCase() + setNewMnemonic(formattedInput) + } + + // Ensure the mnemonic is valid. If it is, then replace the current mnemonic + // in LocalStorage and reload the page. + const handleImportWallet = useCallback(async (event) => { + try { + const mnemonic = newMnemonic + const wallet = appData.wallet + const bchjs = wallet.bchjs + + // Verify the mnemonic is valid. + const isValid = bchjs.Mnemonic.validate(mnemonic, bchjs.Mnemonic.wordLists().english) + if (isValid.includes('is not in wordlist')) { + console.log('Mnemonic is NOT valid') + } else { + console.log('Mnemonic is valid') + } + + // Replace the old mnemonic in LocalStorage with the new one. + appData.updateLocalStorage({ mnemonic }) + // Reload the app. + window.location.reload() + } catch (error) { + console.warn('Error importing wallet: ', error) + } + }, [newMnemonic, appData]) + + return ( + <> + + + + + + +

+ {' '} + Import Wallet +

+
+ + + Enter a 12 word mnemonic below to import your wallet into + this app. The app will reload and use the new mnemonic. + + + + + +
+ + + pasteFromClipboard(e)} + style={{ cursor: 'pointer' }} + /> + +
+ +
+ + + + + + + +
+
+
+
+ +
+
+ + ) +} + +export default WalletImport diff --git a/src/components/app-body/bch-wallet/index.js b/src/components/app-body/bch-wallet/index.js new file mode 100644 index 0000000..e982780 --- /dev/null +++ b/src/components/app-body/bch-wallet/index.js @@ -0,0 +1,47 @@ +/* + This component controlls the Wallet View. +*/ + +// Global npm libraries +import React from 'react' +import { Container, Row, Col } from 'react-bootstrap' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faCircleQuestion } from '@fortawesome/free-solid-svg-icons' + +// Local Libraries +import WebWalletWarning from './warning' +import WalletSummary from './wallet-summary' +import WalletClear from './clear-wallet' +import WalletImport from './import-wallet' +import OptimizeWallet from './optimize-wallet' + +function BchWallet (props) { + // Dependency injection through props + const appData = props.appData + console.log('appData: ', appData) + + return ( + <> + + + + + + + + + + +
+ +
+ +
+ +
+ + + ) +} + +export default BchWallet diff --git a/src/components/app-body/bch-wallet/optimize-wallet.js b/src/components/app-body/bch-wallet/optimize-wallet.js new file mode 100644 index 0000000..42285ce --- /dev/null +++ b/src/components/app-body/bch-wallet/optimize-wallet.js @@ -0,0 +1,113 @@ +/* + This component allows the user to optimize their wallet by consolidating + UTXOs. This speeds up all the network calls and results in an improved UX. +*/ + +// Global npm libraries +import React, { useState } from 'react' +import { Container, Row, Col, Card, Button } from 'react-bootstrap' + +// Local libraries +import WaitingModal from '../../waiting-modal' + +function OptimizeWallet (props) { + // State + const [showModal, setShowModal] = useState(false) + const [modalBody, setModalBody] = useState([]) + const [hideSpinner, setHideSpinner] = useState(false) + const [denyClose, setDenyClose] = useState(false) + + // Get props values + const { wallet } = props.appData + + // Optimize wallet + const handleOptimize = async () => { + console.log('Optimize Wallet button clicked.') + // Show waiting modal + setShowModal(true) + setModalBody(['Optimizing wallet...']) + setDenyClose(true) + + // Optimize wallet + await wallet.optimize() + + // Show success modal + setShowModal(true) + setModalBody(['Your wallet has been optimized!']) + setDenyClose(false) + setHideSpinner(true) + + try { + // Get all UTXOs in the wallet + const utxos = wallet.utxos.utxoStore + console.log('utxos: ', utxos) + + // Add up all the UTXOs + const bchUtxoCnt = utxos.bchUtxos.length + let fungibleUtxoCnt = utxos.slpUtxos.type1.tokens.length + if (!fungibleUtxoCnt) fungibleUtxoCnt = 0 + let nftUtxoCnt = utxos.slpUtxos.nft.length + if (!nftUtxoCnt) nftUtxoCnt = 0 + const totalUtxos = bchUtxoCnt + fungibleUtxoCnt + nftUtxoCnt + console.log(`bchUtxoCnt: ${bchUtxoCnt}, fungibleUtxoCnt: ${fungibleUtxoCnt}, nftUtxoCnt: ${nftUtxoCnt}`) + console.log(`total UTXO count: ${totalUtxos}`) + + if (totalUtxos > 10) { + const newModalBody = [ + 'Your wallet has been optimized!', + 'Your wallet still has more than 10 UTXOs. Increased numbers of UTXOs slow down performance. If you have several tokens in your wallet, it is recommended that you store them in a paper wallet. Here is a video explaining how to do that:' + ] + + newModalBody.push(Video: How to Store SLP Tokens on a Paper Wallet) + newModalBody.push(Generate a Paper Wallet) + + setModalBody(newModalBody) + } + } catch (err) { + console.log('Error while trying to count total number of UTXOs: ', err) + } + } + + return ( + <> + + + + + + +

Optimize Wallet

+
+ + + Clicking the button below will optimize your wallet and make it + function faster. +

+ How it works: By consolidating + as many UTXOs in your wallet as possible, it reduces the total + number of UTXOs in your wallet. Fewer UTXOs in your wallet make + all network calls faster, and results in an improved user experience. +

+ +
+
+
+ +
+
+ + {showModal && ( + + )} + + ) +} + +export default OptimizeWallet diff --git a/src/components/app-body/bch-wallet/wallet-summary.css b/src/components/app-body/bch-wallet/wallet-summary.css new file mode 100644 index 0000000..fcec681 --- /dev/null +++ b/src/components/app-body/bch-wallet/wallet-summary.css @@ -0,0 +1,4 @@ +.blurred { + filter: blur(6px); + -webkit-filter: blur(6px); +} diff --git a/src/components/app-body/bch-wallet/wallet-summary.js b/src/components/app-body/bch-wallet/wallet-summary.js new file mode 100644 index 0000000..998a4dc --- /dev/null +++ b/src/components/app-body/bch-wallet/wallet-summary.js @@ -0,0 +1,165 @@ +/* + This component displays a summary of the wallet. +*/ + +// Global npm libraries +import React, { useState } from 'react' +import { Container, Row, Col, Card } from 'react-bootstrap' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faWallet, faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons' +// import { Clipboard } from '@capacitor/clipboard' + +// Local libraries +import './wallet-summary.css' +import CopyOnClick from './copy-on-click' + +function WalletSummary (props) { + // Props + const appData = props.appData + + const bchWalletState = appData.bchWalletState + console.log('wallet summary state: ', bchWalletState) + + // State + const [blurredMnemonic, setBlurredMnemonic] = useState(true) + const [blurredPrivateKey, setBlurredPrivateKey] = useState(true) + + // Encapsulate component state into an object that can be passed to child functions + const walletSummaryData = { + blurredMnemonic, + setBlurredMnemonic, + blurredPrivateKey, + setBlurredPrivateKey + } + + // Eye icon state + const eyeIcon = { + mnemonic: blurredMnemonic ? faEyeSlash : faEye, + privateKey: blurredPrivateKey ? faEyeSlash : faEye + } + + // Toggle the state of blurring for the mnemonic + const toggleMnemonicBlur = (inObj = {}) => { + try { + const { walletSummaryData } = inObj + + // toggle the state of blurring + const blurredState = walletSummaryData.blurredMnemonic + walletSummaryData.setBlurredMnemonic(!blurredState) + } catch (error) { + console.error('Error toggling mnemonic blur: ', error) + } + } + + // Toggle the state of blurring for the private key + const togglePrivateKeyBlur = (inObj = {}) => { + try { + const { walletSummaryData } = inObj + + // toggle the state of blurring + const blurredState = walletSummaryData.blurredPrivateKey + walletSummaryData.setBlurredPrivateKey(!blurredState) + } catch (error) { + console.error('Error toggling private key blur: ', error) + } + } + + return ( + <> + + + + + + +

+ {' '} + My Wallet +

+
+ + + + Mnemonic: {bchWalletState.mnemonic} + + + toggleMnemonicBlur({ walletSummaryData })} + /> + + + + + + + + + Private Key: {bchWalletState.privateKey} + + + togglePrivateKeyBlur({ walletSummaryData })} + /> + + + + + + + + + Cash Address: {bchWalletState.cashAddress} + + + + + + + + + + SLP Address: {bchWalletState.slpAddress} + + + + + + + + + + Legacy Address: {bchWalletState.legacyAddress} + + + + + + + + + + HD Path: {bchWalletState.hdPath} + + + + + + + +
+
+ + +
+
+ + ) +} + +export default WalletSummary diff --git a/src/components/app-body/bch-wallet/warning.js b/src/components/app-body/bch-wallet/warning.js new file mode 100644 index 0000000..c83d18a --- /dev/null +++ b/src/components/app-body/bch-wallet/warning.js @@ -0,0 +1,49 @@ +/* + This component is a visual warning against storing large sums of money in + a web wallet. +*/ + +// Global npm libraries +import React from 'react' +import { Container, Row, Col, Card } from 'react-bootstrap' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faTriangleExclamation } from '@fortawesome/free-solid-svg-icons' + +const WebWalletWarning = () => { + return ( + <> + + + + + + +

+ {' '} + Web Wallets are Insecure +

+
+ + + This is an open source, non-custodial web wallet + supporting Bitcoin Cash (BCH) and SLP tokens. + It is optimized for convenience and not security. +
+ Do not store large amounts of money on a web wallet. + +

+ Note: Scammers frequently copy this open source code to build + apps for stealing people's money. Be sure you trust the source + serving you this app. +
+
+
+ + +
+
+ + ) +} + +export default WebWalletWarning diff --git a/src/components/app-body/index.js b/src/components/app-body/index.js index eaa1670..a6566be 100644 --- a/src/components/app-body/index.js +++ b/src/components/app-body/index.js @@ -11,6 +11,7 @@ import React from 'react' // Local libraries import GetBalance from './balance' +import Wallet from './bch-wallet' import Placeholder2 from './placeholder2' import Placeholder3 from './placeholder3' import ServerSelectView from './servers/select-server-view' @@ -28,11 +29,13 @@ function AppBody (props) { case 0: return () case 1: - return () + return () case 2: + return () + case 3: return () - // Special Views + // Special Views case 100: return () default: diff --git a/src/components/nav-menu/index.js b/src/components/nav-menu/index.js index 23e8c4e..ed5d95e 100644 --- a/src/components/nav-menu/index.js +++ b/src/components/nav-menu/index.js @@ -35,6 +35,13 @@ function NavMenu (props) { > Check Balance + handleClickEvent(1)} + > + Wallet + { + // console.log(`updateLocalStorage() input: ${JSON.stringify(lsObj, null, 2)}`) + + // Progressively overwrite the LocalStorage state. + const newObj = Object.assign({}, lsState, lsObj) + // console.log(`updateLocalStorage() output: ${JSON.stringify(newObj, null, 2)}`) + + setLSState(newObj) + } + + const [bchWalletState, setBchWalletState] = useState({ + mnemonic: undefined, + address: undefined, + cashAddress: undefined, + slpAddress: undefined, + privateKey: undefined, + publicKey: undefined, + legacyAddress: undefined, + hdPath: undefined, + bchBalance: 0, + slpTokens: [], + bchUsdPrice: 150 + }) + + // This function is passed to child components in order to update the wallet + // state. This function is important to make this wallet a PWA. + function updateBchWalletState (inObj = {}) { + try { + const { walletObj, appData } = inObj + + // Debuging + // console.log('updateBchWalletState() walletObj: ', walletObj) + // console.log('updateBchWalletState() appData: ', appData) + + appData.setBchWalletState(oldState => { + const newBchWalletState = Object.assign({}, oldState, walletObj) + // console.log('newBchWalletState: ', newBchWalletState) + + return newBchWalletState + }) + + // console.log(`New wallet state: ${JSON.stringify(bchWalletState, null, 2)}`) + } catch (err) { + console.error('Error in App.js updateBchWalletState()') + throw err + } + } + return { serverUrl, setServerUrl, @@ -44,7 +105,15 @@ function useAppState () { hideSpinner, setHideSpinner, denyClose, - setDenyClose + setDenyClose, + bchWalletState, + setBchWalletState, + lsState, + setLSState, + removeLocalStorageItem, + updateLocalStorage, + updateBchWalletState, + appUtil: new AppUtil() } } diff --git a/src/services/async-load.js b/src/services/async-load.js index a460474..f5a0b45 100644 --- a/src/services/async-load.js +++ b/src/services/async-load.js @@ -16,73 +16,171 @@ class AsyncLoad { // Load the minimal-slp-wallet which comes in as a