From 9836e4c77e7c409d2a4ac1efed49bf8af3dade04 Mon Sep 17 00:00:00 2001 From: Jordan K <65149726+jordankzf@users.noreply.github.com> Date: Tue, 12 Dec 2023 15:34:27 +0800 Subject: [PATCH 1/8] Parse block seedphrase from clipboard when pasted for devs (#697) Co-authored-by: Tim Man --- src/app/components/seedPhraseInput/index.tsx | 24 ++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/app/components/seedPhraseInput/index.tsx b/src/app/components/seedPhraseInput/index.tsx index 8d51315fb..dee2e7211 100644 --- a/src/app/components/seedPhraseInput/index.tsx +++ b/src/app/components/seedPhraseInput/index.tsx @@ -50,16 +50,24 @@ type SeedWordInputProps = { index: number; handleChangeInput: (e: React.ChangeEvent) => void; handleKeyDownInput: (e: React.KeyboardEvent) => void; + handlePaste: (pastedText: string) => void; disabled?: boolean; }; const SeedWordInput = React.forwardRef( - ({ value, index, handleChangeInput, handleKeyDownInput, disabled }, ref) => { - const [showValue, setShowValue] = useState(false); + ({ value, index, handleChangeInput, handleKeyDownInput, disabled, handlePaste }, ref) => { + const DEV_MODE = process.env.NODE_ENV === 'development'; + const [showValue, setShowValue] = useState(DEV_MODE); const handleFocusInput = () => setShowValue(true); const handleBlurInput = () => setShowValue(false); const handlePasteInput = (e: React.ClipboardEvent) => { e.preventDefault(); + + if (DEV_MODE) { + const { clipboardData } = e; + const pastedText = clipboardData.getData('text'); + handlePaste(pastedText); + } }; return ( @@ -167,6 +175,16 @@ export default function SeedPhraseInput({ }); }; + const handlePaste = (pastedText: string) => { + const splitPastedText = pastedText.split(' '); + splitPastedText.forEach((text, index) => { + setSeedInputValues((prevSeed) => { + prevSeed[index] = text; + return [...prevSeed]; + }); + }); + }; + useEffect(() => { const seedPhrase = seedInputValues .slice(0, !show24Words ? 12 : 24) @@ -190,6 +208,7 @@ export default function SeedPhraseInput({ index={index} handleChangeInput={handleChangeInput(index)} handleKeyDownInput={handleKeyDownInput(index)} + handlePaste={handlePaste} ref={(el) => { inputsRef.current[index] = el; }} @@ -206,6 +225,7 @@ export default function SeedPhraseInput({ index={index} handleChangeInput={handleChangeInput(index)} handleKeyDownInput={handleKeyDownInput(index)} + handlePaste={handlePaste} ref={(el) => { inputsRef.current[index] = el; }} From 71772d9912323d4256adcffb9fed42400809e63b Mon Sep 17 00:00:00 2001 From: Tim Man Date: Wed, 13 Dec 2023 13:14:55 +0800 Subject: [PATCH 2/8] [ENG-3427] fix: allow-404-get-utxos-from-psbt (#709) * fix: allow 404s when checking psbt utxos for ordinals * refactor: move detect ordinal if found logic to core * chore: use beta core version * chore: bump core version to v5.3.0 --- package-lock.json | 39 +++++++-------------- package.json | 2 +- src/app/hooks/useDetectOrdinalInSignPsbt.ts | 7 ++-- 3 files changed, 18 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4e3dc1833..a23843935 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "@ledgerhq/hw-transport-webusb": "^6.27.13", "@phosphor-icons/react": "^2.0.10", "@react-spring/web": "^9.6.1", - "@secretkeylabs/xverse-core": "5.2.0", + "@secretkeylabs/xverse-core": "5.3.0", "@stacks/connect": "^6.10.2", "@stacks/encryption": "4.3.5", "@stacks/stacks-blockchain-api-types": "6.1.1", @@ -1727,9 +1727,9 @@ } }, "node_modules/@secretkeylabs/xverse-core": { - "version": "5.2.0", - "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/5.2.0/f4d46eacac2b7be0b6fb70ce5184d1c10ed7bfa6", - "integrity": "sha512-DhDrTAFYPHf22ThYn+z9DIlxXN6M7jH5JEbAi5I58xE62RsEOcpxfRHDhfNzcNAyWKJEXzChkbOp7OpFHLIF1w==", + "version": "5.3.0", + "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/5.3.0/368b6b101c6dd5d67497dc047a6305afe3812af3", + "integrity": "sha512-cVJJmDgT6d1urtYFugfo7MAHPLmqyk8kO2s81x/KFQhgU6kqhhfu2Oeu71lAAxRc71jvzCYtxF20zj+P6bqEgw==", "license": "ISC", "dependencies": { "@bitcoinerlab/secp256k1": "^1.0.2", @@ -1743,7 +1743,7 @@ "@stacks/transactions": "4.3.5", "@stacks/wallet-sdk": "^5.0.2", "@zondax/ledger-stacks": "^1.0.4", - "axios": "0.27.2", + "axios": "1.4.0", "base64url": "^3.0.1", "bip32": "^4.0.0", "bip39": "3.0.3", @@ -1763,6 +1763,9 @@ "uuidv4": "^6.2.13", "varuint-bitcoin": "^1.1.2" }, + "engines": { + "node": "^18.18.2" + }, "peerDependencies": { "bignumber.js": "^9.0.0", "react": ">18.0.0" @@ -1893,15 +1896,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/@secretkeylabs/xverse-core/node_modules/axios": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", - "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", - "dependencies": { - "follow-redirects": "^1.14.9", - "form-data": "^4.0.0" - } - }, "node_modules/@secretkeylabs/xverse-core/node_modules/base-x": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", @@ -16046,9 +16040,9 @@ } }, "@secretkeylabs/xverse-core": { - "version": "5.2.0", - "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/5.2.0/f4d46eacac2b7be0b6fb70ce5184d1c10ed7bfa6", - "integrity": "sha512-DhDrTAFYPHf22ThYn+z9DIlxXN6M7jH5JEbAi5I58xE62RsEOcpxfRHDhfNzcNAyWKJEXzChkbOp7OpFHLIF1w==", + "version": "5.3.0", + "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/5.3.0/368b6b101c6dd5d67497dc047a6305afe3812af3", + "integrity": "sha512-cVJJmDgT6d1urtYFugfo7MAHPLmqyk8kO2s81x/KFQhgU6kqhhfu2Oeu71lAAxRc71jvzCYtxF20zj+P6bqEgw==", "requires": { "@bitcoinerlab/secp256k1": "^1.0.2", "@noble/secp256k1": "^1.7.1", @@ -16061,7 +16055,7 @@ "@stacks/transactions": "4.3.5", "@stacks/wallet-sdk": "^5.0.2", "@zondax/ledger-stacks": "^1.0.4", - "axios": "0.27.2", + "axios": "1.4.0", "base64url": "^3.0.1", "bip32": "^4.0.0", "bip39": "3.0.3", @@ -16184,15 +16178,6 @@ } } }, - "axios": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", - "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", - "requires": { - "follow-redirects": "^1.14.9", - "form-data": "^4.0.0" - } - }, "base-x": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", diff --git a/package.json b/package.json index c50262364..8ecb9e6ec 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "@ledgerhq/hw-transport-webusb": "^6.27.13", "@phosphor-icons/react": "^2.0.10", "@react-spring/web": "^9.6.1", - "@secretkeylabs/xverse-core": "5.2.0", + "@secretkeylabs/xverse-core": "5.3.0", "@stacks/connect": "^6.10.2", "@stacks/encryption": "4.3.5", "@stacks/stacks-blockchain-api-types": "6.1.1", diff --git a/src/app/hooks/useDetectOrdinalInSignPsbt.ts b/src/app/hooks/useDetectOrdinalInSignPsbt.ts index f4d177820..d4b552e69 100644 --- a/src/app/hooks/useDetectOrdinalInSignPsbt.ts +++ b/src/app/hooks/useDetectOrdinalInSignPsbt.ts @@ -1,6 +1,6 @@ import { Bundle, - getUtxoOrdinalBundle, + getUtxoOrdinalBundleIfFound, mapRareSatsAPIResponseToBundle, ParsedPSBT, } from '@secretkeylabs/xverse-core'; @@ -21,10 +21,13 @@ const useDetectOrdinalInSignPsbt = () => { if (parsedPsbt) { const inputsRequest = parsedPsbt.inputs.map((input) => - getUtxoOrdinalBundle(network.type, input.txid, input.index), + getUtxoOrdinalBundleIfFound(network.type, input.txid, input.index), ); const inputsResponse = await Promise.all(inputsRequest); inputsResponse.forEach((inputResponse, index) => { + if (!inputResponse) { + return; + } const bundle = mapRareSatsAPIResponseToBundle(inputResponse); if ( bundle.inscriptions.length > 0 || From ec09afe60794dc4139ca6664d3bb06ac5cda7fe9 Mon Sep 17 00:00:00 2001 From: Victor Kirov Date: Mon, 18 Dec 2023 04:24:44 +0200 Subject: [PATCH 3/8] Fix account referencing issue on login (#710) --- src/app/components/guards/auth.tsx | 15 +++++++---- src/app/hooks/useWalletReducer.ts | 42 +++++++++++++----------------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/app/components/guards/auth.tsx b/src/app/components/guards/auth.tsx index 839848b77..277a4752b 100644 --- a/src/app/components/guards/auth.tsx +++ b/src/app/components/guards/auth.tsx @@ -1,13 +1,13 @@ -import { PropsWithChildren, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; import useSeedVault from '@hooks/useSeedVault'; import useWalletSelector from '@hooks/useWalletSelector'; -import { useDispatch } from 'react-redux'; import { setWalletUnlockedAction } from '@stores/wallet/actions/actionCreators'; +import { PropsWithChildren, useEffect } from 'react'; +import { useDispatch } from 'react-redux'; +import { useNavigate } from 'react-router-dom'; function AuthGuard({ children }: PropsWithChildren) { const navigate = useNavigate(); - const { masterPubKey, encryptedSeed, isUnlocked } = useWalletSelector(); + const { masterPubKey, encryptedSeed, isUnlocked, accountsList } = useWalletSelector(); const { getSeed, hasSeed } = useSeedVault(); const dispatch = useDispatch(); @@ -26,7 +26,12 @@ function AuthGuard({ children }: PropsWithChildren) { return; } const hasSeedPhrase = await hasSeed(); - if (!hasSeedPhrase || !masterPubKey) { + if ( + !hasSeedPhrase || + // We ensure there is at least 1 account with a masterPubKey as the unlock code will select an account if one + // is not selected in the store + (!masterPubKey && (accountsList.length === 0 || !accountsList[0].masterPubKey)) + ) { navigate('/landing'); return; } diff --git a/src/app/hooks/useWalletReducer.ts b/src/app/hooks/useWalletReducer.ts index 89f923452..7f642674f 100644 --- a/src/app/hooks/useWalletReducer.ts +++ b/src/app/hooks/useWalletReducer.ts @@ -65,6 +65,7 @@ const useWalletReducer = () => { currentAccounts, ); + // we sanitise the account to remove any unknown properties which we had in pervious versions of the app walletAccounts[0] = { id: walletAccounts[0].id, btcAddress: walletAccounts[0].btcAddress, @@ -77,13 +78,18 @@ const useWalletReducer = () => { bnsName: walletAccounts[0].bnsName, }; - let selectedAccountData: Account; + let selectedAccountData: Account | undefined; if (!selectedAccount) { [selectedAccountData] = walletAccounts; } else if (isLedgerAccount(selectedAccount)) { - selectedAccountData = ledgerAccountsList[selectedAccount.id]; + selectedAccountData = ledgerAccountsList.find((a) => a.id === selectedAccount.id); } else { - selectedAccountData = walletAccounts[selectedAccount.id]; + selectedAccountData = walletAccounts.find((a) => a.id === selectedAccount.id); + } + + if (!selectedAccountData) { + // this should not happen but is a good fallback to have, just in case + [selectedAccountData] = walletAccounts; } if (!isHardwareAccount(selectedAccountData)) { @@ -326,36 +332,24 @@ const useWalletReducer = () => { }; const addLedgerAccount = async (ledgerAccount: Account) => { - try { - dispatch(updateLedgerAccountsAction([...ledgerAccountsList, ledgerAccount])); - } catch (err) { - return Promise.reject(err); - } + dispatch(updateLedgerAccountsAction([...ledgerAccountsList, ledgerAccount])); }; const removeLedgerAccount = async (ledgerAccount: Account) => { - try { - dispatch( - updateLedgerAccountsAction( - ledgerAccountsList.filter((account) => account.id !== ledgerAccount.id), - ), - ); - } catch (err) { - return Promise.reject(err); - } + dispatch( + updateLedgerAccountsAction( + ledgerAccountsList.filter((account) => account.id !== ledgerAccount.id), + ), + ); }; const updateLedgerAccounts = async (updatedLedgerAccount: Account) => { const newLedgerAccountsList = ledgerAccountsList.map((account) => account.id === updatedLedgerAccount.id ? updatedLedgerAccount : account, ); - try { - dispatch(updateLedgerAccountsAction(newLedgerAccountsList)); - if (isLedgerAccount(selectedAccount) && updatedLedgerAccount.id === selectedAccount?.id) { - switchAccount(updatedLedgerAccount); - } - } catch (err) { - return Promise.reject(err); + dispatch(updateLedgerAccountsAction(newLedgerAccountsList)); + if (isLedgerAccount(selectedAccount) && updatedLedgerAccount.id === selectedAccount?.id) { + switchAccount(updatedLedgerAccount); } }; From f7e631d7f3d3e874f9618fb9841d0113d6c42d6e Mon Sep 17 00:00:00 2001 From: Mahmoud Aboelenein Date: Mon, 18 Dec 2023 13:31:08 +0200 Subject: [PATCH 4/8] fix nonce not being set correctly for tx requests --- src/app/screens/transactionRequest/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/screens/transactionRequest/index.tsx b/src/app/screens/transactionRequest/index.tsx index ffec77882..6fc4de4e5 100644 --- a/src/app/screens/transactionRequest/index.tsx +++ b/src/app/screens/transactionRequest/index.tsx @@ -51,7 +51,7 @@ function TransactionRequest() { stxPublicKey, feeMultipliers!, selectedNetwork, - stxPendingTxData, + stxPendingTxData.data, ); setUnsignedTx(unsignedSendStxTx); navigate('/confirm-stx-tx', { From bc96e5be365627f5b77a217bc3f445a113051918 Mon Sep 17 00:00:00 2001 From: Denys Hriaznov Date: Mon, 18 Dec 2023 13:08:11 +0100 Subject: [PATCH 5/8] [ENG-3455] fix: Fix the sharp fee change on tx confirmation --- src/app/screens/confirmFtTransaction/index.tsx | 12 +++++++++--- src/app/screens/confirmNftTransaction/index.tsx | 4 ++-- src/app/screens/confirmStxTransaction/index.tsx | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/app/screens/confirmFtTransaction/index.tsx b/src/app/screens/confirmFtTransaction/index.tsx index 70a16c393..00d68aaf6 100644 --- a/src/app/screens/confirmFtTransaction/index.tsx +++ b/src/app/screens/confirmFtTransaction/index.tsx @@ -13,7 +13,7 @@ import { deserializeTransaction } from '@stacks/transactions'; import { useMutation } from '@tanstack/react-query'; import { isLedgerAccount } from '@utils/helper'; import BigNumber from 'bignumber.js'; -import { useEffect } from 'react'; +import { useEffect, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useLocation, useNavigate } from 'react-router-dom'; @@ -22,8 +22,14 @@ function ConfirmFtTransaction() { const navigate = useNavigate(); const selectedNetwork = useNetworkSelector(); const location = useLocation(); - const { unsignedTx: seedHex, amount, fungibleToken, memo, recepientAddress } = location.state; - const unsignedTx = deserializeTransaction(seedHex); + const { + unsignedTx: unsignedTxHex, + amount, + fungibleToken, + memo, + recepientAddress, + } = location.state; + const unsignedTx = useMemo(() => deserializeTransaction(unsignedTxHex), [unsignedTxHex]); const { refetch } = useStxWalletData(); const { network, selectedAccount } = useWalletSelector(); diff --git a/src/app/screens/confirmNftTransaction/index.tsx b/src/app/screens/confirmNftTransaction/index.tsx index d93103bfb..a3f6b209e 100644 --- a/src/app/screens/confirmNftTransaction/index.tsx +++ b/src/app/screens/confirmNftTransaction/index.tsx @@ -17,7 +17,7 @@ import { deserializeTransaction } from '@stacks/transactions'; import { useMutation } from '@tanstack/react-query'; import { isLedgerAccount } from '@utils/helper'; import BigNumber from 'bignumber.js'; -import { useEffect } from 'react'; +import { useEffect, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useLocation, useNavigate, useParams } from 'react-router-dom'; import styled from 'styled-components'; @@ -74,7 +74,7 @@ function ConfirmNftTransaction() { const nft = nftDetailQuery.data?.data; const { unsignedTx: unsignedTxHex, recipientAddress } = location.state; - const unsignedTx = deserializeTransaction(unsignedTxHex); + const unsignedTx = useMemo(() => deserializeTransaction(unsignedTxHex), [unsignedTxHex]); const { network } = useWalletSelector(); const { refetch } = useStxWalletData(); const selectedNetwork = useNetworkSelector(); diff --git a/src/app/screens/confirmStxTransaction/index.tsx b/src/app/screens/confirmStxTransaction/index.tsx index 71d1c03fc..1f1ea17e5 100644 --- a/src/app/screens/confirmStxTransaction/index.tsx +++ b/src/app/screens/confirmStxTransaction/index.tsx @@ -24,7 +24,7 @@ import { deserializeTransaction } from '@stacks/transactions'; import { useMutation } from '@tanstack/react-query'; import { isLedgerAccount } from '@utils/helper'; import BigNumber from 'bignumber.js'; -import { useEffect, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useLocation, useNavigate } from 'react-router-dom'; import styled from 'styled-components'; @@ -49,7 +49,7 @@ function ConfirmStxTransaction() { const location = useLocation(); const selectedNetwork = useNetworkSelector(); const { unsignedTx: stringHex, sponsored, isBrowserTx, tabId, requestToken } = location.state; - const unsignedTx = deserializeTransaction(stringHex); + const unsignedTx = useMemo(() => deserializeTransaction(stringHex), [stringHex]); useOnOriginTabClose(Number(tabId), () => { setHasTabClosed(true); window.scrollTo({ top: 0, behavior: 'smooth' }); From 5cac557b4a6c8cf999eaaeed68c4f853d29eb72b Mon Sep 17 00:00:00 2001 From: Mahmoud Aboelenein Date: Mon, 18 Dec 2023 17:12:31 +0200 Subject: [PATCH 6/8] fix nonce calc persisted --- src/app/screens/transactionRequest/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/screens/transactionRequest/index.tsx b/src/app/screens/transactionRequest/index.tsx index 6fc4de4e5..dff53f42c 100644 --- a/src/app/screens/transactionRequest/index.tsx +++ b/src/app/screens/transactionRequest/index.tsx @@ -1,6 +1,5 @@ import ContractCallRequest from '@components/transactionsRequests/ContractCallRequest'; import ContractDeployRequest from '@components/transactionsRequests/ContractDeployTransaction'; -import useStxPendingTxData from '@hooks/queries/useStxPendingTxData'; import useNetworkSelector from '@hooks/useNetwork'; import useDappRequest from '@hooks/useTransationRequest'; import useWalletReducer from '@hooks/useWalletReducer'; @@ -10,6 +9,7 @@ import { ContractFunction, createDeployContractRequest, extractFromPayload, + fetchStxPendingTxData, } from '@secretkeylabs/xverse-core'; import { StacksTransaction } from '@stacks/transactions'; import { getNetworkType, isHardwareAccount } from '@utils/helper'; @@ -39,11 +39,11 @@ function TransactionRequest() { const [coinsMetaData, setCoinsMetaData] = useState(null); const [codeBody, setCodeBody] = useState(undefined); const [contractName, setContractName] = useState(undefined); - const stxPendingTxData = useStxPendingTxData(); const [hasSwitchedAccount, setHasSwitchedAccount] = useState(false); const [attachment, setAttachment] = useState(undefined); const handleTokenTransferRequest = async () => { + const stxPendingTxData = await fetchStxPendingTxData(stxAddress, selectedNetwork); const unsignedSendStxTx = await getTokenTransferRequest( payload.recipient, payload.amount, @@ -51,7 +51,7 @@ function TransactionRequest() { stxPublicKey, feeMultipliers!, selectedNetwork, - stxPendingTxData.data, + stxPendingTxData || [], ); setUnsignedTx(unsignedSendStxTx); navigate('/confirm-stx-tx', { From de4441a017695707fe264e924efa613be915ab4e Mon Sep 17 00:00:00 2001 From: Yukan Date: Mon, 18 Dec 2023 23:23:10 +0800 Subject: [PATCH 7/8] release v0.26.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8ecb9e6ec..6f68ab457 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "xverse-web-extension", "description": "A Bitcoin wallet for Web3", - "version": "0.26.0", + "version": "0.26.1", "private": true, "engines": { "node": "^18.18.2" From a087c0d242379042b3c42bb9830b01df0d29f16c Mon Sep 17 00:00:00 2001 From: Yukan Date: Mon, 18 Dec 2023 23:29:55 +0800 Subject: [PATCH 8/8] package-lock update --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a23843935..ff73ffab8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "xverse-web-extension", - "version": "0.26.0", + "version": "0.26.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "xverse-web-extension", - "version": "0.26.0", + "version": "0.26.1", "dependencies": { "@ledgerhq/hw-transport-webusb": "^6.27.13", "@phosphor-icons/react": "^2.0.10",