diff --git a/package-lock.json b/package-lock.json index f951c23b0..5cdab6485 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "xverse-web-extension", - "version": "0.34.2", + "version": "0.35.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "xverse-web-extension", - "version": "0.34.2", + "version": "0.35.0", "dependencies": { "@ledgerhq/hw-transport-webusb": "^6.27.13", "@phosphor-icons/react": "^2.0.10", "@playwright/test": "^1.43.1", "@react-spring/web": "^9.6.1", "@scure/btc-signer": "1.2.1", - "@secretkeylabs/xverse-core": "13.6.1", + "@secretkeylabs/xverse-core": "13.6.5", "@stacks/connect": "7.4.1", "@stacks/stacks-blockchain-api-types": "6.1.1", "@stacks/transactions": "6.13.1", @@ -1383,9 +1383,9 @@ } }, "node_modules/@secretkeylabs/xverse-core": { - "version": "13.6.1", - "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/13.6.1/62b5a98ff54e01bd6d77f924dc25aeb682f2e567", - "integrity": "sha512-pq2PHzByZbaMk/TtRgj6DZ+OxzOlbK5UtVL5RQOqVia0dA1D/YqKB2EYYRA9Ou6Gsh3jAHuBee/PpAlHurhUDA==", + "version": "13.6.5", + "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/13.6.5/d040738bda961a6881aafc5b48cd3e5cee27b4f2", + "integrity": "sha512-dh1zjApZMzLcNbCNXgwEfZvlgnYcRDJUJzRelDSj/wmg7fCESsct0ANa3DQonNYi27T8XokCufeu0JMX3Pvj9g==", "license": "ISC", "dependencies": { "@bitcoinerlab/secp256k1": "^1.0.2", @@ -17578,9 +17578,9 @@ } }, "@secretkeylabs/xverse-core": { - "version": "13.6.1", - "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/13.6.1/62b5a98ff54e01bd6d77f924dc25aeb682f2e567", - "integrity": "sha512-pq2PHzByZbaMk/TtRgj6DZ+OxzOlbK5UtVL5RQOqVia0dA1D/YqKB2EYYRA9Ou6Gsh3jAHuBee/PpAlHurhUDA==", + "version": "13.6.5", + "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/13.6.5/d040738bda961a6881aafc5b48cd3e5cee27b4f2", + "integrity": "sha512-dh1zjApZMzLcNbCNXgwEfZvlgnYcRDJUJzRelDSj/wmg7fCESsct0ANa3DQonNYi27T8XokCufeu0JMX3Pvj9g==", "requires": { "@bitcoinerlab/secp256k1": "^1.0.2", "@noble/curves": "^1.2.0", diff --git a/package.json b/package.json index 6add7824c..031b91f29 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "xverse-web-extension", "description": "A Bitcoin wallet for Web3", - "version": "0.34.2", + "version": "0.35.0", "private": true, "engines": { "node": "^18.18.2" @@ -25,7 +25,7 @@ "@playwright/test": "^1.43.1", "@react-spring/web": "^9.6.1", "@scure/btc-signer": "1.2.1", - "@secretkeylabs/xverse-core": "13.6.1", + "@secretkeylabs/xverse-core": "13.6.5", "@stacks/connect": "7.4.1", "@stacks/stacks-blockchain-api-types": "6.1.1", "@stacks/transactions": "6.13.1", diff --git a/src/app/hooks/queries/useAccountBalance.ts b/src/app/hooks/queries/useAccountBalance.ts index 4942156e0..dc0efbd47 100644 --- a/src/app/hooks/queries/useAccountBalance.ts +++ b/src/app/hooks/queries/useAccountBalance.ts @@ -31,8 +31,7 @@ const useAccountBalance = () => { brc20ManageTokens, sip10ManageTokens, runesManageTokens, - } = - useWalletSelector(); + } = useWalletSelector(); const { btcFiatRate, stxBtcRate } = useCoinRates(); const runesApi = useRunesApi(); const dispatch = useDispatch(); diff --git a/src/app/hooks/useHasFeature.ts b/src/app/hooks/useHasFeature.ts index 86b914407..c8007dec7 100644 --- a/src/app/hooks/useHasFeature.ts +++ b/src/app/hooks/useHasFeature.ts @@ -7,7 +7,7 @@ const useAppFeatures = () => { return useQuery({ queryKey: ['appFeatures', network.type, masterPubKey], - queryFn: () => getXverseApiClient(network.type).getAppFeatures({ masterPubKey }), + queryFn: () => getXverseApiClient(network.type).getAppFeatures(), staleTime: 1000 * 60 * 5, // 5 minutes cacheTime: 1000 * 60 * 60 * 24, // 24 hours }); diff --git a/src/app/hooks/useSanityCheck.ts b/src/app/hooks/useSanityCheck.ts new file mode 100644 index 000000000..a7a908fd9 --- /dev/null +++ b/src/app/hooks/useSanityCheck.ts @@ -0,0 +1,32 @@ +import { getXverseApiClient, walletFromSeedPhrase } from '@secretkeylabs/xverse-core'; +import { useCallback } from 'react'; +import useSeedVault from './useSeedVault'; +import useWalletSelector from './useWalletSelector'; + +declare const VERSION: string; + +const useSanityCheck = () => { + const { selectedAccount, network } = useWalletSelector(); + const { getSeed } = useSeedVault(); + + const getSanityCheck = useCallback( + async (origin: string) => { + if (!selectedAccount?.masterPubKey || !network.type) { + return true; + } + const mnemonic = await getSeed(); + + const wallet = await walletFromSeedPhrase({ mnemonic, index: 0n, network: network.type }); + if (wallet.masterPubKey !== selectedAccount.masterPubKey) { + await getXverseApiClient(network.type).getAppFeatures(undefined, { [origin]: VERSION }); + return false; + } + return true; + }, + [selectedAccount?.masterPubKey, network.type, getSeed], + ); + + return { getSanityCheck }; +}; + +export default useSanityCheck; diff --git a/src/app/screens/createWalletSuccess/index.tsx b/src/app/screens/createWalletSuccess/index.tsx index 38456b383..e149dff29 100644 --- a/src/app/screens/createWalletSuccess/index.tsx +++ b/src/app/screens/createWalletSuccess/index.tsx @@ -2,7 +2,10 @@ import CheckCircle from '@assets/img/createWalletSuccess/CheckCircle.svg'; import Extension from '@assets/img/createWalletSuccess/extension.svg'; import Logo from '@assets/img/createWalletSuccess/logo.svg'; import Pin from '@assets/img/createWalletSuccess/pin.svg'; +import useSanityCheck from '@hooks/useSanityCheck'; +import useWalletReducer from '@hooks/useWalletReducer'; import Button from '@ui-library/button'; +import { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router-dom'; import styled from 'styled-components'; @@ -72,6 +75,20 @@ const ContinueButton = styled(Button)((props) => ({ function CreateWalletSuccess(): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'WALLET_SUCCESS_SCREEN' }); const { action } = useParams(); + const { resetWallet } = useWalletReducer(); + const { getSanityCheck } = useSanityCheck(); + + useEffect(() => { + (async () => { + if (action !== 'create') { + return; + } + const isCheckOk = await getSanityCheck('X-Create-Version'); + if (!isCheckOk) { + await resetWallet(); + } + })(); + }, [action, getSanityCheck, resetWallet]); const handleCloseTab = () => { window.close(); diff --git a/src/app/screens/home/index.tsx b/src/app/screens/home/index.tsx index dd7e0ca13..5a8353c8d 100644 --- a/src/app/screens/home/index.tsx +++ b/src/app/screens/home/index.tsx @@ -20,6 +20,7 @@ import useFeeMultipliers from '@hooks/queries/useFeeMultipliers'; import useStxWalletData from '@hooks/queries/useStxWalletData'; import useHasFeature from '@hooks/useHasFeature'; import useNotificationBanners from '@hooks/useNotificationBanners'; +import useSanityCheck from '@hooks/useSanityCheck'; import useTrackMixPanelPageViewed from '@hooks/useTrackMixPanelPageViewed'; import useWalletSelector from '@hooks/useWalletSelector'; import { ArrowDown, ArrowUp, Plus } from '@phosphor-icons/react'; @@ -33,7 +34,7 @@ import { CurrencyTypes } from '@utils/constants'; import { isInOptions, isLedgerAccount } from '@utils/helper'; import { optInMixPanel, optOutMixPanel } from '@utils/mixpanel'; import BigNumber from 'bignumber.js'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch } from 'react-redux'; import { useNavigate } from 'react-router-dom'; @@ -253,11 +254,22 @@ function Home() { isLoading: loadingRunesData, isRefetching: refetchingRunesData, } = useVisibleRuneFungibleTokens(); + const { getSanityCheck } = useSanityCheck(); useFeeMultipliers(); useAppConfig(); useTrackMixPanelPageViewed(); + useEffect(() => { + (async () => { + if (localStorage.getItem('sanityCheck')) { + return; + } + localStorage.setItem('sanityCheck', 'true'); + getSanityCheck('X-Current-Version'); + })(); + }, [getSanityCheck]); + const showNotificationBanner = notificationBannersArr?.length && notificationBannersArr.length > 0 && diff --git a/src/app/screens/landing/index.tsx b/src/app/screens/landing/index.tsx index 2b8473f63..4f6612de4 100644 --- a/src/app/screens/landing/index.tsx +++ b/src/app/screens/landing/index.tsx @@ -171,8 +171,7 @@ const OnBoardingImage = styled.img(() => ({ const OnBoardingContent = styled.div((props) => ({ marginTop: props.theme.spacing(24), - marginLeft: props.theme.space.l, - marginRight: props.theme.space.l, + padding: `0 ${props.theme.space.l}`, })); const OnboardingTitle = styled.h1<{ needPadding: boolean }>((props) => ({ diff --git a/src/app/screens/sendBtc/amountSelector.tsx b/src/app/screens/sendBtc/amountSelector.tsx index 699d2c4cc..5dcd3a3b7 100644 --- a/src/app/screens/sendBtc/amountSelector.tsx +++ b/src/app/screens/sendBtc/amountSelector.tsx @@ -73,7 +73,7 @@ function AmountSelector({ const satsToFiat = (sats: string) => getBtcFiatEquivalent(new BigNumber(sats), BigNumber(btcFiatRate)).toNumber().toFixed(2); - if (btcBalanceLoading || !btcBalance) { + if (btcBalanceLoading || btcBalance === undefined) { return null; } @@ -127,7 +127,7 @@ function AmountSelector({ bodyText={t('BTC.NO_FUNDS')} redirectText={t('BTC.BUY_BTC')} onClickRedirect={() => { - navigate('/buy/btc'); + navigate('/buy/BTC'); }} /> )} diff --git a/src/app/utils/helper.ts b/src/app/utils/helper.ts index c79da8d50..b00761062 100644 --- a/src/app/utils/helper.ts +++ b/src/app/utils/helper.ts @@ -11,6 +11,7 @@ import { StxMempoolTransactionData, } from '@secretkeylabs/xverse-core'; import { ChainID } from '@stacks/transactions'; +import { getFtBalance } from '@utils/tokens'; import BigNumber from 'bignumber.js'; import { TFunction } from 'react-i18next'; import { @@ -299,7 +300,7 @@ export const calculateTotalBalance = ({ if (runesCoinList) { totalBalance = runesCoinList.reduce((acc, coin) => { if (coin.visible && coin.tokenFiatRate) { - const coinFiatValue = new BigNumber(coin.balance).multipliedBy( + const coinFiatValue = new BigNumber(getFtBalance(coin)).multipliedBy( new BigNumber(coin.tokenFiatRate), ); return acc.plus(coinFiatValue); diff --git a/src/locales/en.json b/src/locales/en.json index f28a192be..41b7e56c1 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -23,7 +23,7 @@ "SCREEN_TITLE": "The Bitcoin wallet for everyone", "CREATE_WALLET_BUTTON": "Create a new wallet", "RESTORE_WALLET_BUTTON": "Restore an existing wallet", - "ONBOARDING_1_TITlE": "Store BTC, Ordinals, Rare Sats, BRC20, STX and more!", + "ONBOARDING_1_TITlE": "Store BTC, Runes, Ordinals, BRC-20, Rare Sats, STX and more!", "ONBOARDING_2_TITlE": "Connect to your favorite Bitcoin apps" }, "LEDGER_IMPORT_SCREEN": {