From 0709c02c3aee8e6f0a193d2515431ea6ad2dc60e Mon Sep 17 00:00:00 2001 From: yanguoyu <841185308@qq.com> Date: Thu, 27 Jul 2023 13:40:45 +0800 Subject: [PATCH 1/2] feat: Add set light client start block number --- .../ImportHardware/findDevice.module.scss | 4 + .../components/ImportHardware/name-wallet.tsx | 6 +- .../src/components/ImportKeystore/index.tsx | 2 + .../src/components/NetworkStatus/index.tsx | 72 ------------ .../NetworkStatus/networkStatus.module.scss | 107 ----------------- .../src/components/Overview/index.tsx | 2 +- .../src/components/PageContainer/hooks.ts | 109 ++++++++++++++++++ .../src/components/PageContainer/index.tsx | 99 ++++++++++------ .../PageContainer/pageContainer.module.scss | 19 +++ .../src/components/SyncStatus/index.tsx | 38 +++++- .../SyncStatus/syncStatus.module.scss | 22 ++-- .../src/components/WalletWizard/index.tsx | 5 +- .../neuron-ui/src/containers/Main/hooks.ts | 18 ++- .../neuron-ui/src/containers/Main/index.tsx | 17 ++- packages/neuron-ui/src/locales/en.json | 10 +- packages/neuron-ui/src/locales/zh-tw.json | 10 +- packages/neuron-ui/src/locales/zh.json | 10 +- packages/neuron-ui/src/services/localCache.ts | 14 +++ .../neuron-ui/src/services/remote/hardware.ts | 2 +- .../src/stories/NetworkStatus.stories.tsx | 94 --------------- .../neuron-ui/src/types/Controller/index.d.ts | 1 + packages/neuron-ui/src/utils/const.ts | 1 + packages/neuron-ui/src/utils/is.ts | 5 +- .../neuron-ui/src/widgets/Dialog/index.tsx | 12 +- .../src/widgets/Icons/StartBlock.svg | 3 + .../neuron-ui/src/widgets/Icons/new_tab.svg | 5 +- .../neuron-ui/src/widgets/TextField/index.tsx | 1 + .../neuron-ui/src/widgets/Tooltip/index.tsx | 10 +- .../sync/light-connector.ts | 21 ++-- packages/neuron-wallet/src/controllers/api.ts | 29 ++++- .../neuron-wallet/src/controllers/wallets.ts | 12 +- .../database/chain/entities/sync-progress.ts | 2 +- .../1690361215400-AddWalletPrimary.ts | 20 ++++ .../src/database/chain/ormconfig.ts | 2 + .../src/models/subjects/data-update.ts | 2 +- .../neuron-wallet/src/services/wallets.ts | 10 +- 36 files changed, 427 insertions(+), 369 deletions(-) delete mode 100644 packages/neuron-ui/src/components/NetworkStatus/index.tsx delete mode 100644 packages/neuron-ui/src/components/NetworkStatus/networkStatus.module.scss create mode 100644 packages/neuron-ui/src/components/PageContainer/hooks.ts delete mode 100644 packages/neuron-ui/src/stories/NetworkStatus.stories.tsx create mode 100644 packages/neuron-ui/src/widgets/Icons/StartBlock.svg create mode 100644 packages/neuron-wallet/src/database/chain/migrations/1690361215400-AddWalletPrimary.ts diff --git a/packages/neuron-ui/src/components/ImportHardware/findDevice.module.scss b/packages/neuron-ui/src/components/ImportHardware/findDevice.module.scss index 8dc55427de..cec5e65ec2 100644 --- a/packages/neuron-ui/src/components/ImportHardware/findDevice.module.scss +++ b/packages/neuron-ui/src/components/ImportHardware/findDevice.module.scss @@ -12,6 +12,10 @@ flex-direction: column; align-items: center; + .name { + width: 480px; + } + .selectDevice { display: flex; flex-direction: column; diff --git a/packages/neuron-ui/src/components/ImportHardware/name-wallet.tsx b/packages/neuron-ui/src/components/ImportHardware/name-wallet.tsx index 7452b7231d..6c1215c095 100644 --- a/packages/neuron-ui/src/components/ImportHardware/name-wallet.tsx +++ b/packages/neuron-ui/src/components/ImportHardware/name-wallet.tsx @@ -6,6 +6,7 @@ import { createHardwareWallet } from 'services/remote' import { CONSTANTS, isSuccessResponse, useDialogWrapper } from 'utils' import Alert from 'widgets/Alert' import { FinishCreateLoading, getAlertStatus } from 'components/WalletWizard' +import { importedWalletDialogShown } from 'services/localCache' import { ImportStep, ActionType, ImportHardwareState } from './common' import styles from './findDevice.module.scss' @@ -41,6 +42,9 @@ const NameWallet = ({ .then(res => { if (isSuccessResponse(res)) { dispatch({ step: ImportStep.Success }) + if (res.result) { + importedWalletDialogShown.init(res.result.id) + } } else { setErrorMsg(typeof res.message === 'string' ? res.message : res.message!.content!) } @@ -60,7 +64,7 @@ const NameWallet = ({ return (
{t('import-hardware.title.name-wallet')}
-
+
{ importKeystore({ name: fields.name!, keystorePath: fields.path, password: fields.password }) .then(res => { if (isSuccessResponse(res)) { + importedWalletDialogShown.init(res.result.id) navigate(window.neuron.role === 'main' ? RoutePath.Overview : RoutePath.SettingsWallets) return } diff --git a/packages/neuron-ui/src/components/NetworkStatus/index.tsx b/packages/neuron-ui/src/components/NetworkStatus/index.tsx deleted file mode 100644 index 2a3c9b575e..0000000000 --- a/packages/neuron-ui/src/components/NetworkStatus/index.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react' -import { useTranslation } from 'react-i18next' -import NetworkTypeLabel from 'components/NetworkTypeLabel' -import { NewTab } from 'widgets/Icons/icon' -import styles from './networkStatus.module.scss' - -export interface NetworkStatusProps { - isMigrate?: boolean - network: State.Network | undefined - syncPercents: number - syncBlockNumbers: string - onAction: (e: React.SyntheticEvent) => void - isLookingValidTarget: boolean - onOpenValidTarget: (e: React.SyntheticEvent) => void -} - -const NetworkStatus = ({ - network, - syncPercents, - syncBlockNumbers, - onAction, - isLookingValidTarget, - onOpenValidTarget, - isMigrate, -}: NetworkStatusProps) => { - const [t] = useTranslation() - - return ( -
- {network && !isMigrate ? ( -
-
- {t('network-status.tooltip.block-synced')} - {`${syncPercents}%`} -
- {syncBlockNumbers} - {isLookingValidTarget && ( -
- {t('network-status.tooltip.looking-valid-target')} - -
- )} -
- ) : null} - {isMigrate &&
{t('network-status.migrating')}
} - {network ? ( -
- - {network.name} -
- ) : ( - {t('settings.setting-tabs.network')} - )} -
- ) -} - -NetworkStatus.displayName = 'NetworkStatus' -export default NetworkStatus diff --git a/packages/neuron-ui/src/components/NetworkStatus/networkStatus.module.scss b/packages/neuron-ui/src/components/NetworkStatus/networkStatus.module.scss deleted file mode 100644 index 95fd700a2b..0000000000 --- a/packages/neuron-ui/src/components/NetworkStatus/networkStatus.module.scss +++ /dev/null @@ -1,107 +0,0 @@ -@import '../../styles/mixin.scss'; -$hover-bg-color: #3cc68a4d; - -.network { - position: relative; - display: flex; - align-items: center; - color: #fff; - font-size: 0.8rem; - font-weight: bold; - - .networkDisplay { - max-width: 100%; - - .name { - position: relative; - display: block; - line-height: 16px; - word-break: break-all; - overflow-wrap: break-word; - margin-top: 3px; - } - } - - /* keep the tooltip popped to make it more obvious */ - & { - .tooltip { - display: flex; - opacity: 1; - } - } - span[class^='label'] { - margin-left: 0; - padding: 0; - height: 0.9rem; - letter-spacing: 0.45px; - } -} - -.tooltip { - @include medium-text; - display: none; - position: absolute; - bottom: calc(100% + 10px); - left: 12px; - flex-direction: column; - background-color: #fff; - color: #000; - min-width: 176px; - padding: 5px 10px; - border-radius: 1px; - box-sizing: border-box; - box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.22); - transition: all 0.2s ease-in-out; - opacity: 0; - pointer-events: none; - font-size: 0.75rem; - line-height: 1.25em; - white-space: nowrap; - z-index: 10; - - .tooltipTitle { - grid-area: title; - word-wrap: none; - word-break: keep-all; - font-weight: 900; - display: flex; - justify-content: space-between; - } - - .blockNumber { - justify-self: flex-end; - text-align: right; - padding-left: 30px; - } - - &::after { - position: absolute; - top: 100%; - left: 60px; - display: block; - content: ''; - border: 10px solid transparent; - border-top-color: #fff; - } - - .lookingValidTarget { - display: flex; - align-items: center; - pointer-events: initial; - - .openTarget { - width: 14px; - height: 14px; - } - } -} - -@keyframes rotate { - from { - transform: rotate(0); - } - - to { - transform: rotate(359deg); - } -} diff --git a/packages/neuron-ui/src/components/Overview/index.tsx b/packages/neuron-ui/src/components/Overview/index.tsx index 436e109dea..f5f3eabb21 100644 --- a/packages/neuron-ui/src/components/Overview/index.tsx +++ b/packages/neuron-ui/src/components/Overview/index.tsx @@ -197,7 +197,7 @@ const Overview = () => { }, [setShowBalance]) return ( - +
diff --git a/packages/neuron-ui/src/components/PageContainer/hooks.ts b/packages/neuron-ui/src/components/PageContainer/hooks.ts new file mode 100644 index 0000000000..5b9fc7cb4a --- /dev/null +++ b/packages/neuron-ui/src/components/PageContainer/hooks.ts @@ -0,0 +1,109 @@ +import { useCallback, useEffect, useState } from 'react' +import { importedWalletDialogShown } from 'services/localCache' +import { isDark, openExternal, updateWallet, setTheme as setThemeAPI } from 'services/remote' +import { Migrate } from 'services/subjects' +import { getExplorerUrl, isSuccessResponse } from 'utils' + +export const useSetBlockNumber = ({ + firstAddress, + walletID, + isMainnet, + isLightClient, + isHomePage, +}: { + firstAddress: string + walletID: string + isMainnet: boolean + isLightClient: boolean + isHomePage?: boolean +}) => { + const [showSetStartBlock, setShowSetStartBlock] = useState(false) + const [startBlockNumber, setStartBlockNumber] = useState('') + const [blockNumberErr, setBlockNumberErr] = useState('') + const onChangeStartBlockNumber = useCallback((e: React.SyntheticEvent) => { + const { value } = e.currentTarget + const blockNumber = value.replace(/,/g, '') + if (Number.isNaN(+blockNumber) || /[^\d]/.test(blockNumber)) { + return + } + setStartBlockNumber(blockNumber) + setBlockNumberErr('') + }, []) + const onOpenAddressInExplorer = useCallback(() => { + const explorerUrl = getExplorerUrl(isMainnet) + openExternal(`${explorerUrl}/address/${firstAddress}`) + }, [firstAddress]) + const onViewBlock = useCallback(() => { + const explorerUrl = getExplorerUrl(isMainnet) + openExternal(`${explorerUrl}/block/${startBlockNumber}`) + }, [startBlockNumber, isMainnet]) + const onConfirm = useCallback(() => { + updateWallet({ id: walletID, startBlockNumberInLight: `0x${BigInt(startBlockNumber).toString(16)}` }).then(res => { + if (isSuccessResponse(res)) { + setShowSetStartBlock(false) + } else { + setBlockNumberErr(typeof res.message === 'string' ? res.message : res.message.content!) + } + }) + }, [startBlockNumber, walletID]) + const openDialog = useCallback(() => { + setShowSetStartBlock(true) + setStartBlockNumber('') + }, []) + useEffect(() => { + if (isHomePage) { + const needShow = importedWalletDialogShown.needShow(walletID) + if (needShow && isLightClient) { + openDialog() + } + importedWalletDialogShown.setShown(walletID) + } + }, [walletID, isLightClient, isHomePage, openDialog]) + return { + openDialog, + closeDialog: useCallback(() => setShowSetStartBlock(false), []), + showSetStartBlock, + startBlockNumber, + onChangeStartBlockNumber, + onOpenAddressInExplorer, + onViewBlock, + onConfirm, + blockNumberErr, + } +} + +export const useTheme = () => { + const [theme, setTheme] = useState<'dark' | 'light'>() + useEffect(() => { + isDark().then(res => { + if (isSuccessResponse(res)) { + setTheme(res.result ? 'dark' : 'light') + } + }) + }, []) + const onSetTheme = useCallback(() => { + const newTheme = theme === 'dark' ? 'light' : 'dark' + setThemeAPI(newTheme).then(res => { + if (isSuccessResponse(res)) { + setTheme(newTheme) + } + }) + }, [theme]) + return { + theme, + onSetTheme, + } +} + +export const useMigrate = () => { + const [isMigrate, setIsMigrate] = useState(false) + useEffect(() => { + const migrateSubscription = Migrate.subscribe(migrateStatus => { + setIsMigrate(migrateStatus === 'migrating') + }) + return () => { + migrateSubscription.unsubscribe() + } + }, []) + return isMigrate +} diff --git a/packages/neuron-ui/src/components/PageContainer/index.tsx b/packages/neuron-ui/src/components/PageContainer/index.tsx index 3a37d105c2..e2fa9eca70 100755 --- a/packages/neuron-ui/src/components/PageContainer/index.tsx +++ b/packages/neuron-ui/src/components/PageContainer/index.tsx @@ -1,15 +1,19 @@ -import React, { FC, PropsWithChildren, useCallback, useEffect, useMemo, useState } from 'react' +import React, { FC, PropsWithChildren, useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' -import { ErrorCode, getExplorerUrl, isMainnet, isSuccessResponse, localNumberFormatter } from 'utils' +import { ErrorCode, getExplorerUrl, isMainnet as isMainnetUtil, localNumberFormatter } from 'utils' import Alert from 'widgets/Alert' -import { Close } from 'widgets/Icons/icon' +import { Close, NewTab } from 'widgets/Icons/icon' import { ReactComponent as Sun } from 'widgets/Icons/Sun.svg' import { ReactComponent as Moon } from 'widgets/Icons/Moon.svg' import SyncStatusComponent from 'components/SyncStatus' import { AppActions, useDispatch, useState as useGlobalState } from 'states' -import { isDark, openExternal, setTheme as setThemeAPI } from 'services/remote' +import { openExternal } from 'services/remote' import Tooltip from 'widgets/Tooltip' -import { Migrate } from 'services/subjects' +import { LIGHT_NETWORK_TYPE } from 'utils/const' +import Dialog from 'widgets/Dialog' +import TextField from 'widgets/TextField' + +import { useMigrate, useSetBlockNumber, useTheme } from './hooks' import styles from './pageContainer.module.scss' const PageHeadNotice = ({ notice }: { notice: State.PageNotice }) => { @@ -39,6 +43,7 @@ type ComponentProps = { head: React.ReactNode notice?: State.PageNotice className?: string + isHomePage?: boolean } & React.AllHTMLAttributes const PageContainer: React.FC = props => { const { @@ -48,9 +53,10 @@ const PageContainer: React.FC = props => { connectionStatus, networkID, }, + wallet: { addresses, id }, settings: { networks }, } = useGlobalState() - const { children, head, notice, className } = props + const { children, head, notice, className, isHomePage } = props const [t] = useTranslation() const dispatch = useDispatch() const closeSyncNotice = useCallback(() => { @@ -58,23 +64,12 @@ const PageContainer: React.FC = props => { type: AppActions.HideWaitForFullySynced, }) }, [dispatch]) - const [theme, setTheme] = useState<'dark' | 'light'>() - useEffect(() => { - isDark().then(res => { - if (isSuccessResponse(res)) { - setTheme(res.result ? 'dark' : 'light') - } - }) - }, []) - const onSetTheme = useCallback(() => { - const newTheme = theme === 'dark' ? 'light' : 'dark' - setThemeAPI(newTheme).then(res => { - if (isSuccessResponse(res)) { - setTheme(newTheme) - } - }) - }, [theme]) + const { theme, onSetTheme } = useTheme() const network = useMemo(() => networks.find(n => n.id === networkID), [networks, networkID]) + const isLightClient = useMemo( + () => networks.find(n => n.id === networkID)?.type === LIGHT_NETWORK_TYPE, + [networkID, networks] + ) const netWorkTypeLabel = useMemo(() => (network ? getNetworkTypeLabel(network.chain) : ''), [network]) const [syncPercents, syncBlockNumbers] = useMemo(() => { const bestBlockNumber = Math.max(cacheTipBlockNumber, bestKnownBlockNumber) @@ -87,23 +82,32 @@ const PageContainer: React.FC = props => { }`, ] }, [cacheTipBlockNumber, bestKnownBlockNumber]) + const isMainnet = useMemo(() => isMainnetUtil(networks, networkID), [networks, networkID]) const onOpenValidTarget = useCallback( (e: React.SyntheticEvent) => { e.stopPropagation() - const explorerUrl = getExplorerUrl(isMainnet(networks, networkID)) + const explorerUrl = getExplorerUrl(isMainnet) openExternal(`${explorerUrl}/block/${validTarget}`) }, - [networks, networkID, validTarget] + [isMainnet, validTarget] ) - const [isMigrate, setIsMigrate] = useState(false) - useEffect(() => { - const migrateSubscription = Migrate.subscribe(migrateStatus => { - setIsMigrate(migrateStatus === 'migrating') - }) - return () => { - migrateSubscription.unsubscribe() - } - }, []) + const isMigrate = useMigrate() + const { + showSetStartBlock, + openDialog, + closeDialog, + onChangeStartBlockNumber, + startBlockNumber, + onOpenAddressInExplorer, + onViewBlock, + onConfirm, + } = useSetBlockNumber({ + firstAddress: addresses[0]?.address, + isMainnet, + isLightClient, + walletID: id, + isHomePage, + }) return (
@@ -136,6 +140,8 @@ const PageContainer: React.FC = props => { isLookingValidTarget={isLookingValidTarget} onOpenValidTarget={onOpenValidTarget} isMigrate={isMigrate} + isLightClient={isLightClient} + onOpenSetStartBlock={openDialog} />
@@ -148,6 +154,33 @@ const PageContainer: React.FC = props => { )}
{children}
+ +

{t('set-start-block-number.tip')}

+ + {t('set-start-block-number.view-block')} + + + ) : ( + + ) + } + /> +
) } diff --git a/packages/neuron-ui/src/components/PageContainer/pageContainer.module.scss b/packages/neuron-ui/src/components/PageContainer/pageContainer.module.scss index 98a148e1bf..e104030a7b 100755 --- a/packages/neuron-ui/src/components/PageContainer/pageContainer.module.scss +++ b/packages/neuron-ui/src/components/PageContainer/pageContainer.module.scss @@ -168,3 +168,22 @@ color: var(--main-text-color); } } + +.startBlockTip { + font-weight: 400; + color: var(--secondary-text-color); +} + +.viewAction { + border: none; + background-color: transparent; + cursor: pointer; + color: var(--primary-color); + display: flex; + align-items: center; + + & > svg { + width: 12px; + height: 12px; + } +} diff --git a/packages/neuron-ui/src/components/SyncStatus/index.tsx b/packages/neuron-ui/src/components/SyncStatus/index.tsx index a6f3307449..6ff0fb9f70 100644 --- a/packages/neuron-ui/src/components/SyncStatus/index.tsx +++ b/packages/neuron-ui/src/components/SyncStatus/index.tsx @@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next' import { SyncStatus as SyncStatusEnum, ConnectionStatus } from 'utils' import { Confirming, NewTab } from 'widgets/Icons/icon' import { ReactComponent as UnexpandStatus } from 'widgets/Icons/UnexpandStatus.svg' +import { ReactComponent as StartBlock } from 'widgets/Icons/StartBlock.svg' import Tooltip from 'widgets/Tooltip' import styles from './syncStatus.module.scss' @@ -10,10 +11,14 @@ const SyncDetail = ({ syncBlockNumbers, isLookingValidTarget, onOpenValidTarget, + isLightClient, + onOpenSetStartBlock, }: { syncBlockNumbers: string isLookingValidTarget: boolean onOpenValidTarget: (e: React.SyntheticEvent) => void + isLightClient: boolean + onOpenSetStartBlock: () => void }) => { const [t] = useTranslation() return ( @@ -26,7 +31,7 @@ const SyncDetail = ({ {isLookingValidTarget && (
)} + {isLightClient && ( +
+
+ {t('network-status.tooltip.set-start-block-number')} + +
+
+ )} ) } @@ -49,6 +68,8 @@ const SyncStatus = ({ isLookingValidTarget, onOpenValidTarget, isMigrate, + isLightClient, + onOpenSetStartBlock, }: React.PropsWithoutRef<{ syncStatus: SyncStatusEnum connectionStatus: State.ConnectionStatus @@ -57,12 +78,14 @@ const SyncStatus = ({ isLookingValidTarget: boolean onOpenValidTarget: (e: React.SyntheticEvent) => void isMigrate: boolean + isLightClient: boolean + onOpenSetStartBlock: () => void }>) => { const [t] = useTranslation() const [isOpen, setIsOpen] = useState(false) - const onChangeIsOpen = useCallback(() => { - setIsOpen(v => !v) - }, [setIsOpen]) + const onVisibleChange = useCallback((v: boolean) => { + setIsOpen(v) + }, []) if (isMigrate) { return {t('network-status.migrating')} @@ -91,20 +114,23 @@ const SyncStatus = ({ syncBlockNumbers={syncBlockNumbers} isLookingValidTarget={isLookingValidTarget} onOpenValidTarget={onOpenValidTarget} + isLightClient={isLightClient} + onOpenSetStartBlock={onOpenSetStartBlock} /> } trigger="click" className={styles.tipContainer} tipClassName={styles.tip} + onVisibleChange={onVisibleChange} showTriangle > {SyncStatusEnum.SyncCompleted === syncStatus ? ( - ) : ( -
)}
{t(message)}
- {submissionInputs.map(input => ( + {submissionInputs.map((input, idx) => (
diff --git a/packages/neuron-ui/src/containers/Main/hooks.ts b/packages/neuron-ui/src/containers/Main/hooks.ts index 17f47bd15b..b146956af2 100644 --- a/packages/neuron-ui/src/containers/Main/hooks.ts +++ b/packages/neuron-ui/src/containers/Main/hooks.ts @@ -9,7 +9,7 @@ import { initAppState, } from 'states/stateProvider/actionCreators' -import { getWinID } from 'services/remote' +import { getCurrentWallet, getWinID } from 'services/remote' import { DataUpdate as DataUpdateSubject, NetworkList as NetworkListSubject, @@ -19,9 +19,13 @@ import { Command as CommandSubject, } from 'services/subjects' import { ckbCore, getTipHeader } from 'services/chain' -import { networks as networksCache, currentNetworkID as currentNetworkIDCache } from 'services/localCache' +import { + networks as networksCache, + currentNetworkID as currentNetworkIDCache, + importedWalletDialogShown, +} from 'services/localCache' import { WalletWizardPath } from 'components/WalletWizard' -import { ErrorCode, RoutePath, getConnectionStatus } from 'utils' +import { ErrorCode, RoutePath, getConnectionStatus, isSuccessResponse } from 'utils' const SYNC_INTERVAL_TIME = 4000 const CONNECTING_BUFFER = 15_000 @@ -153,6 +157,14 @@ export const useSubscription = ({ }) break } + case 'new-xpubkey-wallet': { + getCurrentWallet().then(res => { + if (isSuccessResponse(res) && res.result) { + importedWalletDialogShown.init(res.result.id) + } + }) + break + } case 'wallets': { Promise.all([updateWalletList, updateCurrentWallet].map(request => request()(dispatch))).then( ([hasList, hasCurrent]) => { diff --git a/packages/neuron-ui/src/containers/Main/index.tsx b/packages/neuron-ui/src/containers/Main/index.tsx index 78eeb46abd..48ec40b027 100644 --- a/packages/neuron-ui/src/containers/Main/index.tsx +++ b/packages/neuron-ui/src/containers/Main/index.tsx @@ -1,15 +1,16 @@ -import React, { useMemo } from 'react' +import React, { useCallback, useMemo } from 'react' import { useNavigate, useLocation, Outlet } from 'react-router-dom' import { useTranslation } from 'react-i18next' -import { useState as useGlobalState, useDispatch } from 'states' +import { useState as useGlobalState, useDispatch, dismissAlertDialog } from 'states' import { useOnDefaultContextMenu, useOnLocaleChange } from 'utils' +import AlertDialog from 'widgets/AlertDialog' import { useSubscription, useSyncChainData, useOnCurrentWalletChange } from './hooks' const MainContent = () => { const navigate = useNavigate() const location = useLocation() const { - app: { isAllowedToFetchList = true }, + app: { isAllowedToFetchList = true, alertDialog }, wallet: { id: walletID = '' }, chain, settings: { networks = [] }, @@ -45,10 +46,20 @@ const MainContent = () => { }) useOnLocaleChange(i18n) const onContextMenu = useOnDefaultContextMenu(t) + const onCancelGlobalDialog = useCallback(() => { + dismissAlertDialog()(dispatch) + }, [dispatch]) return (
+
) } diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index 9450151e06..df5f5d4ef1 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -27,7 +27,8 @@ "network-status": { "tooltip": { "block-synced": "Block Synced", - "looking-valid-target": "Looking for assumed valid target" + "looking-valid-target": "Looking for assumed valid target", + "set-start-block-number": "Set start block number" }, "migrating": "migrating..." }, @@ -1110,6 +1111,13 @@ "countDownTip": "The price will refresh after {{countDown}} seconds", "switchToCustomPrice": "Switch to custom price", "switchToPrice": "Switch to price" + }, + "set-start-block-number": { + "title": "Set the start block number", + "tip": "The start sync block number is configuration when use light client ckb node, then you can set it and quick the sync", + "input-place-holder": "Please enter the start sync block number, eg: 10,100,101", + "locate-first-tx": "Locate the first transaction", + "view-block": "View the block" } } } diff --git a/packages/neuron-ui/src/locales/zh-tw.json b/packages/neuron-ui/src/locales/zh-tw.json index 4a437feb2e..cb26246994 100644 --- a/packages/neuron-ui/src/locales/zh-tw.json +++ b/packages/neuron-ui/src/locales/zh-tw.json @@ -27,7 +27,8 @@ "network-status": { "tooltip": { "block-synced": "已同步區塊", - "looking-valid-target": "尋找預設可信區塊" + "looking-valid-target": "尋找預設可信區塊", + "set-start-block-number": "設置同步起始區塊" }, "migrating": "正在數據遷移..." }, @@ -1080,6 +1081,13 @@ "countDownTip": "單價將在{{countDown}}秒後刷新", "switchToCustomPrice": "切換到自定義價格", "switchToPrice": "切換到單價" + }, + "set-start-block-number": { + "title": "設置同步起始區塊", + "tip": "輕客戶端模式下的訂閱起始點是可配置的,因此您可以設置同步起始區塊以加快同步速度。", + "input-place-holder": "輸入同步起始區塊號,例如:10,100,101", + "locate-first-tx": "定位到第壹筆交易", + "view-block": "查看區塊" } } } diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index 2d00fcaf72..0c550f3120 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -27,7 +27,8 @@ "network-status": { "tooltip": { "block-synced": "已同步区块", - "looking-valid-target": "寻找预设可信区块" + "looking-valid-target": "寻找预设可信区块", + "set-start-block-number": "设置同步起始区块" }, "migrating": "正在数据迁移..." }, @@ -1102,6 +1103,13 @@ "countDownTip": "单价将在{{countDown}}秒后刷新", "switchToCustomPrice": "切换到自定义价格", "switchToPrice": "切换到单价" + }, + "set-start-block-number": { + "title": "设置同步起始区块", + "tip": "轻客户端模式下的订阅起始点是可配置的,因此您可以设置同步起始区块以加快同步速度。", + "input-place-holder": "输入同步起始区块号,例如:10,100,101", + "locate-first-tx": "定位到第一笔交易", + "view-block": "查看区块" } } } diff --git a/packages/neuron-ui/src/services/localCache.ts b/packages/neuron-ui/src/services/localCache.ts index aead05ecf8..e7f95746fc 100644 --- a/packages/neuron-ui/src/services/localCache.ts +++ b/packages/neuron-ui/src/services/localCache.ts @@ -9,6 +9,7 @@ export enum LocalCacheKey { CacheClearDate = 'cacheClearDate', SyncRebuildNotification = 'syncRebuildNotification', FirstLoadApp = 'FirstLoadApp', + ImportedWallet = 'ImportedWallet', } export const addresses = { @@ -138,3 +139,16 @@ export const firstLoadApp = { return window.localStorage.getItem(LocalCacheKey.FirstLoadApp) !== 'false' }, } + +export const importedWalletDialogShown = { + getKey: (walletId: string) => `${walletId}_${LocalCacheKey.ImportedWallet}`, + init: (walletId: string) => { + window.localStorage.setItem(importedWalletDialogShown.getKey(walletId), 'false') + }, + setShown: (walletId: string) => { + window.localStorage.setItem(importedWalletDialogShown.getKey(walletId), 'true') + }, + needShow: (walletId: string) => { + return window.localStorage.getItem(importedWalletDialogShown.getKey(walletId)) === 'false' + }, +} diff --git a/packages/neuron-ui/src/services/remote/hardware.ts b/packages/neuron-ui/src/services/remote/hardware.ts index 146bc24888..c0c1cf19d8 100644 --- a/packages/neuron-ui/src/services/remote/hardware.ts +++ b/packages/neuron-ui/src/services/remote/hardware.ts @@ -36,6 +36,6 @@ export const getDeviceFirmwareVersion = remoteApi('get-devi export const getDeviceExtendedPublickey = remoteApi('get-device-extended-public-key') export const getDevicePublicKey = remoteApi('get-device-public-key') export const connectDevice = remoteApi('connect-device') -export const createHardwareWallet = remoteApi( +export const createHardwareWallet = remoteApi( 'create-hardware-wallet' ) diff --git a/packages/neuron-ui/src/stories/NetworkStatus.stories.tsx b/packages/neuron-ui/src/stories/NetworkStatus.stories.tsx deleted file mode 100644 index 7c40df09db..0000000000 --- a/packages/neuron-ui/src/stories/NetworkStatus.stories.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react' -import NetworkStatus, { NetworkStatusProps } from 'components/NetworkStatus' - -const defaultProps: Omit = { - network: { - name: 'network', - remote: 'http://127.0.0.1:3000', - type: 0, - id: 'd', - chain: 'ckb', - genesisHash: '0x10639e0895502b5688a6be8cf69460d76541bfa4821629d86d62ba0aae3f9606', - }, - onAction: () => {}, - isLookingValidTarget: false, - onOpenValidTarget: () => {}, -} - -const meta: Meta = { - component: NetworkStatus, - parameters: { - layout: 'padded', - paddings: { - values: [ - { name: 'Small', value: '16px' }, - { name: 'Medium', value: '32px' }, - { name: 'Large', value: '64px' }, - ], - default: 'Medium', - }, - }, -} - -export default meta - -type Story = StoryObj - -export const Online: Story = { - args: { - ...defaultProps, - syncPercents: 1, - syncBlockNumbers: '1/200', - }, -} - -export const Offline: Story = { - args: { - ...defaultProps, - syncPercents: 1, - syncBlockNumbers: '1/100', - }, -} - -export const isLookingValidTarget: Story = { - args: { - ...defaultProps, - syncPercents: 1, - syncBlockNumbers: '1/100', - isLookingValidTarget: true, - }, -} - -export const SyncedFinishedAndNotip: Story = { - args: { - ...defaultProps, - syncPercents: 100, - syncBlockNumbers: '100/0', - }, - storyName: '100 synced and 0 tip', -} - -export const SyncedFinishedAndEmptytip: Story = { - args: { - ...defaultProps, - syncPercents: 100, - syncBlockNumbers: '-/100', - }, - storyName: '100 synced and empty tip', -} - -export const NotSycnedAnd100Tip: Story = { - args: { - ...defaultProps, - syncPercents: 0, - syncBlockNumbers: '-/100', - }, -} - -export const NotSyncedAndEmptyTip: Story = { - args: { - ...defaultProps, - syncPercents: 0, - syncBlockNumbers: '-/-', - }, -} diff --git a/packages/neuron-ui/src/types/Controller/index.d.ts b/packages/neuron-ui/src/types/Controller/index.d.ts index db60d4b099..64f4a46c3f 100644 --- a/packages/neuron-ui/src/types/Controller/index.d.ts +++ b/packages/neuron-ui/src/types/Controller/index.d.ts @@ -35,6 +35,7 @@ declare namespace Controller { newPassword?: string name?: string device?: any + startBlockNumberInLight?: string } interface RequestPasswordParams { diff --git a/packages/neuron-ui/src/utils/const.ts b/packages/neuron-ui/src/utils/const.ts index e351c54d7d..abd90e982b 100644 --- a/packages/neuron-ui/src/utils/const.ts +++ b/packages/neuron-ui/src/utils/const.ts @@ -14,6 +14,7 @@ export const BUFFER_BLOCK_NUMBER = 10 export const MAX_DECIMAL_DIGITS = 8 export const MAINNET_TAG = 'ckb' +export const LIGHT_MAINNET_TAG = 'light_client_mainnet' export const MIN_DEPOSIT_AMOUNT = 102 export const TOKEN_ID_LENGTH = 66 diff --git a/packages/neuron-ui/src/utils/is.ts b/packages/neuron-ui/src/utils/is.ts index 7c4a960365..1975ddf3ba 100644 --- a/packages/neuron-ui/src/utils/is.ts +++ b/packages/neuron-ui/src/utils/is.ts @@ -8,10 +8,11 @@ import { PwAcpLockInfoOnMainNet, PwAcpLockInfoOnTestNet, } from 'utils/enums' -import { MAINNET_TAG } from './const' +import { LIGHT_MAINNET_TAG, MAINNET_TAG } from './const' export const isMainnet = (networks: Readonly, networkID: string) => { - return (networks.find(n => n.id === networkID) || {}).chain === MAINNET_TAG + const network = networks.find(n => n.id === networkID) + return network?.chain === MAINNET_TAG || network?.chain === LIGHT_MAINNET_TAG } export const isSuccessResponse = (res: Pick): res is SuccessFromController => { diff --git a/packages/neuron-ui/src/widgets/Dialog/index.tsx b/packages/neuron-ui/src/widgets/Dialog/index.tsx index f94a40c2c2..c2c9b17dc8 100644 --- a/packages/neuron-ui/src/widgets/Dialog/index.tsx +++ b/packages/neuron-ui/src/widgets/Dialog/index.tsx @@ -14,7 +14,7 @@ interface DialogProps { confirmText?: string cancelText?: string disabled?: boolean | undefined - children?: React.ReactChild + children?: React.ReactNode isLoading?: boolean confirmProps?: object showHeader?: boolean @@ -58,15 +58,6 @@ const Dialog = ({ } }, [show]) - const onDialogClicked = useCallback( - (e: React.MouseEvent) => { - if (e.target instanceof HTMLDialogElement && e.target.tagName === 'DIALOG') { - onCancel?.() - } - }, - [onCancel] - ) - const handleConfirm = useCallback( (e: React.FormEvent) => { e.preventDefault() @@ -86,7 +77,6 @@ const Dialog = ({ (e.key === 'Escape' && enableCloseWithEsc ? onCancel : undefined)} role="none" > diff --git a/packages/neuron-ui/src/widgets/Icons/StartBlock.svg b/packages/neuron-ui/src/widgets/Icons/StartBlock.svg new file mode 100644 index 0000000000..b471c35120 --- /dev/null +++ b/packages/neuron-ui/src/widgets/Icons/StartBlock.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/neuron-ui/src/widgets/Icons/new_tab.svg b/packages/neuron-ui/src/widgets/Icons/new_tab.svg index 00c3eabeb6..31a013c284 100644 --- a/packages/neuron-ui/src/widgets/Icons/new_tab.svg +++ b/packages/neuron-ui/src/widgets/Icons/new_tab.svg @@ -1,2 +1,3 @@ - \ No newline at end of file + + + diff --git a/packages/neuron-ui/src/widgets/TextField/index.tsx b/packages/neuron-ui/src/widgets/TextField/index.tsx index a686fde066..e0a98ea991 100644 --- a/packages/neuron-ui/src/widgets/TextField/index.tsx +++ b/packages/neuron-ui/src/widgets/TextField/index.tsx @@ -50,6 +50,7 @@ const TextField = React.forwardRef( width?: string rows?: number errorWithIcon?: boolean + tabIndex?: number }, ref: React.LegacyRef ) => { diff --git a/packages/neuron-ui/src/widgets/Tooltip/index.tsx b/packages/neuron-ui/src/widgets/Tooltip/index.tsx index b887f32ce7..c4140812b0 100644 --- a/packages/neuron-ui/src/widgets/Tooltip/index.tsx +++ b/packages/neuron-ui/src/widgets/Tooltip/index.tsx @@ -14,6 +14,7 @@ interface TooltipProps { type?: 'normal' | 'always-dark' showTriangle?: boolean isTriggerNextToChild?: boolean + onVisibleChange?: (visible: boolean) => void } const Tooltip: React.FC = ({ children, @@ -26,17 +27,22 @@ const Tooltip: React.FC = ({ type = 'normal', showTriangle, isTriggerNextToChild, + onVisibleChange, }) => { const [isTipShow, setIsTipShow] = useState(false) const ref = useRef(null) const onChangeIsTipShow = useCallback(() => { - setIsTipShow(v => !v) - }, [setIsTipShow]) + setIsTipShow(v => { + onVisibleChange?.(!v) + return !v + }) + }, [setIsTipShow, onVisibleChange]) const onDocumentClick = useCallback( (e: MouseEvent) => { if (e.target instanceof Node && !ref.current?.contains(e.target)) { setIsTipShow(false) + onVisibleChange?.(false) } }, [isTipShow] diff --git a/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts b/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts index 86c145809e..d1685697b5 100644 --- a/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts +++ b/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts @@ -185,13 +185,20 @@ export default class LightConnector extends Connector { ) const otherTypeSyncProgress = await SyncProgressService.getOtherTypeSyncProgress() const setScriptsParams = [ - ...allScripts.map(v => ({ - ...v, - blockNumber: - existSyncscripts[scriptToHash(v.script)]?.blockNumber ?? - walletStartBlockMap[v.walletId] ?? - `0x${(walletMinBlockNumber?.[v.walletId] ?? 0).toString(16)}`, - })), + ...allScripts.map(v => { + let syncedBlockNumber = existSyncscripts[scriptToHash(v.script)]?.blockNumber + const walletStartBlockNumber = walletStartBlockMap[v.walletId] + if ( + walletStartBlockNumber && + (!syncedBlockNumber || BigInt(syncedBlockNumber) < BigInt(walletStartBlockNumber)) + ) { + syncedBlockNumber = walletStartBlockNumber + } + return { + ...v, + blockNumber: syncedBlockNumber ?? `0x${(walletMinBlockNumber?.[v.walletId] ?? 0).toString(16)}`, + } + }), ...appendScripts.map(v => ({ ...v, blockNumber: diff --git a/packages/neuron-wallet/src/controllers/api.ts b/packages/neuron-wallet/src/controllers/api.ts index 8ccd7626ec..246bc4505a 100644 --- a/packages/neuron-wallet/src/controllers/api.ts +++ b/packages/neuron-wallet/src/controllers/api.ts @@ -60,6 +60,8 @@ import startMonitor, { stopMonitor } from '../services/monitor' import { migrateCkbData } from '../services/ckb-runner' import NodeService from '../services/node' import SyncProgressService from '../services/sync-progress' +import { resetSyncTaskQueue } from '../block-sync-renderer' +import DataUpdateSubject from '../models/subjects/data-update' export type Command = 'export-xpubkey' | 'import-xpubkey' | 'delete-wallet' | 'backup-wallet' | 'migrate-acp' // Handle channel messages from renderer process and user actions. @@ -93,9 +95,14 @@ export default class ApiController { break } case 'import-xpubkey': { - this.#walletsController.importXPubkey().catch(error => { - dialog.showMessageBox({ type: 'error', buttons: [], message: error.message }) - }) + this.#walletsController + .importXPubkey() + .then(() => { + DataUpdateSubject.next({ dataType: 'new-xpubkey-wallet', actionType: 'create' }) + }) + .catch(error => { + dialog.showMessageBox({ type: 'error', buttons: [], message: error.message }) + }) break } case 'delete-wallet': @@ -315,9 +322,19 @@ export default class ApiController { return this.#walletsController.create(params) }) - handle('update-wallet', async (_, params: { id: string; password: string; name: string; newPassword?: string }) => { - return this.#walletsController.update(params) - }) + handle( + 'update-wallet', + async ( + _, + params: { id: string; password?: string; name?: string; newPassword?: string; startBlockNumberInLight?: string } + ) => { + const res = this.#walletsController.update(params) + if (params.startBlockNumberInLight) { + resetSyncTaskQueue.asyncPush(true) + } + return res + } + ) handle('delete-wallet', async (_, { id = '', password = '' }) => { return this.#walletsController.delete({ id, password }) diff --git a/packages/neuron-wallet/src/controllers/wallets.ts b/packages/neuron-wallet/src/controllers/wallets.ts index 7f22e8db50..ddd77c3548 100644 --- a/packages/neuron-wallet/src/controllers/wallets.ts +++ b/packages/neuron-wallet/src/controllers/wallets.ts @@ -199,12 +199,14 @@ export default class WalletsController { password, newPassword, device, + startBlockNumberInLight, }: { id: string - password: string - name: string + password?: string + name?: string newPassword?: string device?: DeviceInfo + startBlockNumberInLight?: string }): Promise> { const walletsService = WalletsService.getInstance() const wallet = walletsService.get(id) @@ -212,8 +214,9 @@ export default class WalletsController { throw new WalletNotFound(id) } - const props: { name: string; keystore?: Keystore; device?: DeviceInfo } = { + const props: { name: string; keystore?: Keystore; device?: DeviceInfo; startBlockNumberInLight?: string } = { name: name || wallet.name, + startBlockNumberInLight, } if (!wallet.isHardware()) { @@ -225,6 +228,9 @@ export default class WalletsController { } if (newPassword) { + if (!password) { + throw new Error('Change password need old password') + } const extendedPrivateKey = wallet!.loadKeystore().extendedPrivateKey(password) props.keystore = Keystore.create(extendedPrivateKey, newPassword) } diff --git a/packages/neuron-wallet/src/database/chain/entities/sync-progress.ts b/packages/neuron-wallet/src/database/chain/entities/sync-progress.ts index 552778becd..33ec2f8118 100644 --- a/packages/neuron-wallet/src/database/chain/entities/sync-progress.ts +++ b/packages/neuron-wallet/src/database/chain/entities/sync-progress.ts @@ -24,7 +24,7 @@ export default class SyncProgress { @Column() scriptType!: CKBRPC.ScriptType - @Column({ type: 'varchar' }) + @PrimaryColumn({ type: 'varchar' }) walletId!: string @Column() diff --git a/packages/neuron-wallet/src/database/chain/migrations/1690361215400-AddWalletPrimary.ts b/packages/neuron-wallet/src/database/chain/migrations/1690361215400-AddWalletPrimary.ts new file mode 100644 index 0000000000..bebc08053c --- /dev/null +++ b/packages/neuron-wallet/src/database/chain/migrations/1690361215400-AddWalletPrimary.ts @@ -0,0 +1,20 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; +import SyncProgress from "../entities/sync-progress"; + +export class AddWalletPrimary1690361215400 implements MigrationInterface { + name = 'AddWalletPrimary1690361215400' + + public async up(queryRunner: QueryRunner): Promise { + const syncProgresses = await queryRunner.manager.find(SyncProgress) + await queryRunner.query(`DROP TABLE "sync_progress"`) + await queryRunner.query(`CREATE TABLE "sync_progress" ("hash" varchar NOT NULL, "args" varchar NOT NULL, "codeHash" varchar NOT NULL, "hashType" varchar NOT NULL, "scriptType" varchar NOT NULL, "walletId" varchar NOT NULL, "blockStartNumber" integer NOT NULL, "blockEndNumber" integer, "cursor" varchar, "delete" boolean, "addressType" integer, PRIMARY KEY ("hash", "walletId"))`) + for (let index = 0; index < syncProgresses.length; index += 500) { + await queryRunner.manager.save(syncProgresses.slice(index, index + 500)) + } + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE "sync_progress"`) + } + +} diff --git a/packages/neuron-wallet/src/database/chain/ormconfig.ts b/packages/neuron-wallet/src/database/chain/ormconfig.ts index 311135e7d9..0ba6af467a 100644 --- a/packages/neuron-wallet/src/database/chain/ormconfig.ts +++ b/packages/neuron-wallet/src/database/chain/ormconfig.ts @@ -53,6 +53,7 @@ import { RemoveAddressesMultisigConfig1651820157100 } from './migrations/1651820 import { AddSyncProgress1676441837373 } from './migrations/1676441837373-AddSyncProgress' import { AddTypeSyncProgress1681360188494 } from './migrations/1681360188494-AddTypeSyncProgress' import { TxLock1684488676083 } from './migrations/1684488676083-TxLock' +import { AddWalletPrimary1690361215400 } from './migrations/1690361215400-AddWalletPrimary' export const CONNECTION_NOT_FOUND_NAME = 'ConnectionNotFoundError' @@ -122,6 +123,7 @@ const connectOptions = async (genesisBlockHash: string): Promise() diff --git a/packages/neuron-wallet/src/services/wallets.ts b/packages/neuron-wallet/src/services/wallets.ts index d754aa0b36..3fed2c7336 100644 --- a/packages/neuron-wallet/src/services/wallets.ts +++ b/packages/neuron-wallet/src/services/wallets.ts @@ -66,6 +66,7 @@ export abstract class Wallet { extendedKey: this.extendedKey, device: this.device, isHD: this.isHD, + startBlockNumberInLight: this.startBlockNumberInLight, }) public fromJSON = () => { @@ -92,13 +93,20 @@ export abstract class Wallet { throw new WalletFunctionNotSupported(this.accountExtendedPublicKey.name) } - public update = ({ name, device }: Pick) => { + public update = ({ + name, + device, + startBlockNumberInLight, + }: Pick, 'name' | 'device' | 'startBlockNumberInLight'>) => { if (name) { this.name = name } if (device) { this.device = device } + if (startBlockNumberInLight) { + this.startBlockNumberInLight = startBlockNumberInLight + } } public abstract checkAndGenerateAddresses( From e97bfecfa45a769fb81a4d200278d333b3962e13 Mon Sep 17 00:00:00 2001 From: yanguoyu <841185308@qq.com> Date: Wed, 2 Aug 2023 22:43:39 +0800 Subject: [PATCH 2/2] fix: Resolve review conversations 1. Rename `startBlockNumberInLight` to `startBlockNumber`. 2. Change transaction 3. Better variable name and function name. --- .../components/ImportHardware/name-wallet.tsx | 2 +- .../src/components/ImportKeystore/index.tsx | 2 +- .../src/components/PageContainer/hooks.ts | 19 +++++++++--------- .../src/components/PageContainer/index.tsx | 4 ++-- .../src/components/WalletWizard/index.tsx | 2 +- .../neuron-ui/src/containers/Main/hooks.ts | 2 +- packages/neuron-ui/src/locales/zh-tw.json | 4 ++-- packages/neuron-ui/src/locales/zh.json | 4 ++-- packages/neuron-ui/src/services/localCache.ts | 16 ++++++++------- .../neuron-ui/src/types/Controller/index.d.ts | 2 +- .../sync/light-connector.ts | 2 +- packages/neuron-wallet/src/controllers/api.ts | 4 ++-- .../neuron-wallet/src/controllers/wallets.ts | 18 ++++++++--------- ...0361215400-ResetSyncProgressPrimaryKey.ts} | 4 ++-- .../src/database/chain/ormconfig.ts | 4 ++-- .../neuron-wallet/src/services/wallets.ts | 20 +++++++++---------- .../light-connector.test.ts | 2 +- 17 files changed, 57 insertions(+), 54 deletions(-) rename packages/neuron-wallet/src/database/chain/migrations/{1690361215400-AddWalletPrimary.ts => 1690361215400-ResetSyncProgressPrimaryKey.ts} (87%) diff --git a/packages/neuron-ui/src/components/ImportHardware/name-wallet.tsx b/packages/neuron-ui/src/components/ImportHardware/name-wallet.tsx index 6c1215c095..5960236158 100644 --- a/packages/neuron-ui/src/components/ImportHardware/name-wallet.tsx +++ b/packages/neuron-ui/src/components/ImportHardware/name-wallet.tsx @@ -43,7 +43,7 @@ const NameWallet = ({ if (isSuccessResponse(res)) { dispatch({ step: ImportStep.Success }) if (res.result) { - importedWalletDialogShown.init(res.result.id) + importedWalletDialogShown.setStatus(res.result.id, true) } } else { setErrorMsg(typeof res.message === 'string' ? res.message : res.message!.content!) diff --git a/packages/neuron-ui/src/components/ImportKeystore/index.tsx b/packages/neuron-ui/src/components/ImportKeystore/index.tsx index 324bb97a91..464fe4e9cc 100644 --- a/packages/neuron-ui/src/components/ImportKeystore/index.tsx +++ b/packages/neuron-ui/src/components/ImportKeystore/index.tsx @@ -106,7 +106,7 @@ const ImportKeystore = () => { importKeystore({ name: fields.name!, keystorePath: fields.path, password: fields.password }) .then(res => { if (isSuccessResponse(res)) { - importedWalletDialogShown.init(res.result.id) + importedWalletDialogShown.setStatus(res.result.id, true) navigate(window.neuron.role === 'main' ? RoutePath.Overview : RoutePath.SettingsWallets) return } diff --git a/packages/neuron-ui/src/components/PageContainer/hooks.ts b/packages/neuron-ui/src/components/PageContainer/hooks.ts index 5b9fc7cb4a..9ebd050afe 100644 --- a/packages/neuron-ui/src/components/PageContainer/hooks.ts +++ b/packages/neuron-ui/src/components/PageContainer/hooks.ts @@ -17,7 +17,7 @@ export const useSetBlockNumber = ({ isLightClient: boolean isHomePage?: boolean }) => { - const [showSetStartBlock, setShowSetStartBlock] = useState(false) + const [isSetStartBlockShown, setIsSetStartBlockShown] = useState(false) const [startBlockNumber, setStartBlockNumber] = useState('') const [blockNumberErr, setBlockNumberErr] = useState('') const onChangeStartBlockNumber = useCallback((e: React.SyntheticEvent) => { @@ -32,37 +32,38 @@ export const useSetBlockNumber = ({ const onOpenAddressInExplorer = useCallback(() => { const explorerUrl = getExplorerUrl(isMainnet) openExternal(`${explorerUrl}/address/${firstAddress}`) - }, [firstAddress]) + }, [firstAddress, isMainnet]) const onViewBlock = useCallback(() => { const explorerUrl = getExplorerUrl(isMainnet) openExternal(`${explorerUrl}/block/${startBlockNumber}`) }, [startBlockNumber, isMainnet]) const onConfirm = useCallback(() => { - updateWallet({ id: walletID, startBlockNumberInLight: `0x${BigInt(startBlockNumber).toString(16)}` }).then(res => { + updateWallet({ id: walletID, startBlockNumber: `0x${BigInt(startBlockNumber).toString(16)}` }).then(res => { if (isSuccessResponse(res)) { - setShowSetStartBlock(false) + setIsSetStartBlockShown(false) } else { setBlockNumberErr(typeof res.message === 'string' ? res.message : res.message.content!) } }) }, [startBlockNumber, walletID]) const openDialog = useCallback(() => { - setShowSetStartBlock(true) + setIsSetStartBlockShown(true) setStartBlockNumber('') + setBlockNumberErr('') }, []) useEffect(() => { if (isHomePage) { - const needShow = importedWalletDialogShown.needShow(walletID) + const needShow = importedWalletDialogShown.getStatus(walletID) if (needShow && isLightClient) { openDialog() } - importedWalletDialogShown.setShown(walletID) + importedWalletDialogShown.setStatus(walletID, false) } }, [walletID, isLightClient, isHomePage, openDialog]) return { openDialog, - closeDialog: useCallback(() => setShowSetStartBlock(false), []), - showSetStartBlock, + closeDialog: useCallback(() => setIsSetStartBlockShown(false), []), + isSetStartBlockShown, startBlockNumber, onChangeStartBlockNumber, onOpenAddressInExplorer, diff --git a/packages/neuron-ui/src/components/PageContainer/index.tsx b/packages/neuron-ui/src/components/PageContainer/index.tsx index e2fa9eca70..c51ffd6923 100755 --- a/packages/neuron-ui/src/components/PageContainer/index.tsx +++ b/packages/neuron-ui/src/components/PageContainer/index.tsx @@ -93,7 +93,7 @@ const PageContainer: React.FC = props => { ) const isMigrate = useMigrate() const { - showSetStartBlock, + isSetStartBlockShown, openDialog, closeDialog, onChangeStartBlockNumber, @@ -156,7 +156,7 @@ const PageContainer: React.FC = props => {
{children}
diff --git a/packages/neuron-ui/src/components/WalletWizard/index.tsx b/packages/neuron-ui/src/components/WalletWizard/index.tsx index 355dfe7019..28074f33e9 100644 --- a/packages/neuron-ui/src/components/WalletWizard/index.tsx +++ b/packages/neuron-ui/src/components/WalletWizard/index.tsx @@ -46,7 +46,7 @@ const createWalletWithMnemonic = (params: Controller.ImportMnemonicParams) => (n const importWalletWithMnemonic = (params: Controller.ImportMnemonicParams) => (navigate: NavigateFunction) => { return importMnemonic(params).then(res => { if (isSuccessResponse(res)) { - importedWalletDialogShown.init(res.result.id) + importedWalletDialogShown.setStatus(res.result.id, true) navigate(window.neuron.role === 'main' ? RoutePath.Overview : RoutePath.SettingsWallets) } else if (res.status > 0) { showErrorMessage(i18n.t(`messages.error`), i18n.t(`messages.codes.${res.status}`)) diff --git a/packages/neuron-ui/src/containers/Main/hooks.ts b/packages/neuron-ui/src/containers/Main/hooks.ts index b146956af2..c0df39fb61 100644 --- a/packages/neuron-ui/src/containers/Main/hooks.ts +++ b/packages/neuron-ui/src/containers/Main/hooks.ts @@ -160,7 +160,7 @@ export const useSubscription = ({ case 'new-xpubkey-wallet': { getCurrentWallet().then(res => { if (isSuccessResponse(res) && res.result) { - importedWalletDialogShown.init(res.result.id) + importedWalletDialogShown.setStatus(res.result.id, true) } }) break diff --git a/packages/neuron-ui/src/locales/zh-tw.json b/packages/neuron-ui/src/locales/zh-tw.json index cb26246994..5373900479 100644 --- a/packages/neuron-ui/src/locales/zh-tw.json +++ b/packages/neuron-ui/src/locales/zh-tw.json @@ -1085,8 +1085,8 @@ "set-start-block-number": { "title": "設置同步起始區塊", "tip": "輕客戶端模式下的訂閱起始點是可配置的,因此您可以設置同步起始區塊以加快同步速度。", - "input-place-holder": "輸入同步起始區塊號,例如:10,100,101", - "locate-first-tx": "定位到第壹筆交易", + "input-place-holder": "輸入同步起始區塊高度,例如:10,100,101", + "locate-first-tx": "定位第一筆交易", "view-block": "查看區塊" } } diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index 0c550f3120..6784dc5981 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -1107,8 +1107,8 @@ "set-start-block-number": { "title": "设置同步起始区块", "tip": "轻客户端模式下的订阅起始点是可配置的,因此您可以设置同步起始区块以加快同步速度。", - "input-place-holder": "输入同步起始区块号,例如:10,100,101", - "locate-first-tx": "定位到第一笔交易", + "input-place-holder": "输入同步起始区块高度,例如:10,100,101", + "locate-first-tx": "定位第一笔交易", "view-block": "查看区块" } } diff --git a/packages/neuron-ui/src/services/localCache.ts b/packages/neuron-ui/src/services/localCache.ts index e7f95746fc..893035a3f3 100644 --- a/packages/neuron-ui/src/services/localCache.ts +++ b/packages/neuron-ui/src/services/localCache.ts @@ -142,13 +142,15 @@ export const firstLoadApp = { export const importedWalletDialogShown = { getKey: (walletId: string) => `${walletId}_${LocalCacheKey.ImportedWallet}`, - init: (walletId: string) => { - window.localStorage.setItem(importedWalletDialogShown.getKey(walletId), 'false') + setStatus: (walletId: string, show: boolean) => { + window.localStorage.setItem(importedWalletDialogShown.getKey(walletId), show.toString()) }, - setShown: (walletId: string) => { - window.localStorage.setItem(importedWalletDialogShown.getKey(walletId), 'true') - }, - needShow: (walletId: string) => { - return window.localStorage.getItem(importedWalletDialogShown.getKey(walletId)) === 'false' + getStatus: (walletId: string) => { + try { + const status = window.localStorage.getItem(importedWalletDialogShown.getKey(walletId)) + return status ? (JSON.parse(status) as boolean) : false + } catch (error) { + return false + } }, } diff --git a/packages/neuron-ui/src/types/Controller/index.d.ts b/packages/neuron-ui/src/types/Controller/index.d.ts index 64f4a46c3f..31ee5e7d11 100644 --- a/packages/neuron-ui/src/types/Controller/index.d.ts +++ b/packages/neuron-ui/src/types/Controller/index.d.ts @@ -35,7 +35,7 @@ declare namespace Controller { newPassword?: string name?: string device?: any - startBlockNumberInLight?: string + startBlockNumber?: string } interface RequestPasswordParams { diff --git a/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts b/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts index d1685697b5..7978388fb9 100644 --- a/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts +++ b/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts @@ -180,7 +180,7 @@ export default class LightConnector extends Connector { const walletMinBlockNumber = await SyncProgressService.getWalletMinBlockNumber() const wallets = await WalletService.getInstance().getAll() const walletStartBlockMap = wallets.reduce>( - (pre, cur) => ({ ...pre, [cur.id]: cur.startBlockNumberInLight }), + (pre, cur) => ({ ...pre, [cur.id]: cur.startBlockNumber }), {} ) const otherTypeSyncProgress = await SyncProgressService.getOtherTypeSyncProgress() diff --git a/packages/neuron-wallet/src/controllers/api.ts b/packages/neuron-wallet/src/controllers/api.ts index 246bc4505a..c3731851b9 100644 --- a/packages/neuron-wallet/src/controllers/api.ts +++ b/packages/neuron-wallet/src/controllers/api.ts @@ -326,10 +326,10 @@ export default class ApiController { 'update-wallet', async ( _, - params: { id: string; password?: string; name?: string; newPassword?: string; startBlockNumberInLight?: string } + params: { id: string; password?: string; name?: string; newPassword?: string; startBlockNumber?: string } ) => { const res = this.#walletsController.update(params) - if (params.startBlockNumberInLight) { + if (params.startBlockNumber) { resetSyncTaskQueue.asyncPush(true) } return res diff --git a/packages/neuron-wallet/src/controllers/wallets.ts b/packages/neuron-wallet/src/controllers/wallets.ts index ddd77c3548..be7cc8a78c 100644 --- a/packages/neuron-wallet/src/controllers/wallets.ts +++ b/packages/neuron-wallet/src/controllers/wallets.ts @@ -120,12 +120,12 @@ export default class WalletsController { const walletsService = WalletsService.getInstance() const rpc = generateRPC(NodeService.getInstance().nodeUrl) - let startBlockNumberInLight: string | undefined = undefined + let startBlockNumber: string | undefined = undefined if (!isImporting) { try { - startBlockNumberInLight = await rpc.getTipBlockNumber() + startBlockNumber = await rpc.getTipBlockNumber() } catch (error) { - startBlockNumberInLight = undefined + startBlockNumber = undefined } } const wallet = walletsService.create({ @@ -133,7 +133,7 @@ export default class WalletsController { name, extendedKey: accountExtendedPublicKey.serialize(), keystore, - startBlockNumberInLight, + startBlockNumber: startBlockNumber, }) wallet.checkAndGenerateAddresses(isImporting) @@ -199,14 +199,14 @@ export default class WalletsController { password, newPassword, device, - startBlockNumberInLight, + startBlockNumber, }: { id: string password?: string name?: string newPassword?: string device?: DeviceInfo - startBlockNumberInLight?: string + startBlockNumber?: string }): Promise> { const walletsService = WalletsService.getInstance() const wallet = walletsService.get(id) @@ -214,9 +214,9 @@ export default class WalletsController { throw new WalletNotFound(id) } - const props: { name: string; keystore?: Keystore; device?: DeviceInfo; startBlockNumberInLight?: string } = { + const props: { name: string; keystore?: Keystore; device?: DeviceInfo; startBlockNumber?: string } = { name: name || wallet.name, - startBlockNumberInLight, + startBlockNumber, } if (!wallet.isHardware()) { @@ -229,7 +229,7 @@ export default class WalletsController { if (newPassword) { if (!password) { - throw new Error('Change password need old password') + throw new Error('Old password is required to set a new password') } const extendedPrivateKey = wallet!.loadKeystore().extendedPrivateKey(password) props.keystore = Keystore.create(extendedPrivateKey, newPassword) diff --git a/packages/neuron-wallet/src/database/chain/migrations/1690361215400-AddWalletPrimary.ts b/packages/neuron-wallet/src/database/chain/migrations/1690361215400-ResetSyncProgressPrimaryKey.ts similarity index 87% rename from packages/neuron-wallet/src/database/chain/migrations/1690361215400-AddWalletPrimary.ts rename to packages/neuron-wallet/src/database/chain/migrations/1690361215400-ResetSyncProgressPrimaryKey.ts index bebc08053c..17bbd1cef2 100644 --- a/packages/neuron-wallet/src/database/chain/migrations/1690361215400-AddWalletPrimary.ts +++ b/packages/neuron-wallet/src/database/chain/migrations/1690361215400-ResetSyncProgressPrimaryKey.ts @@ -1,8 +1,8 @@ import {MigrationInterface, QueryRunner} from "typeorm"; import SyncProgress from "../entities/sync-progress"; -export class AddWalletPrimary1690361215400 implements MigrationInterface { - name = 'AddWalletPrimary1690361215400' +export class ResetSyncProgressPrimaryKey1690361215400 implements MigrationInterface { + name = 'ResetSyncProgressPrimaryKey1690361215400' public async up(queryRunner: QueryRunner): Promise { const syncProgresses = await queryRunner.manager.find(SyncProgress) diff --git a/packages/neuron-wallet/src/database/chain/ormconfig.ts b/packages/neuron-wallet/src/database/chain/ormconfig.ts index 0ba6af467a..78f0502a68 100644 --- a/packages/neuron-wallet/src/database/chain/ormconfig.ts +++ b/packages/neuron-wallet/src/database/chain/ormconfig.ts @@ -53,7 +53,7 @@ import { RemoveAddressesMultisigConfig1651820157100 } from './migrations/1651820 import { AddSyncProgress1676441837373 } from './migrations/1676441837373-AddSyncProgress' import { AddTypeSyncProgress1681360188494 } from './migrations/1681360188494-AddTypeSyncProgress' import { TxLock1684488676083 } from './migrations/1684488676083-TxLock' -import { AddWalletPrimary1690361215400 } from './migrations/1690361215400-AddWalletPrimary' +import { ResetSyncProgressPrimaryKey1690361215400 } from './migrations/1690361215400-ResetSyncProgressPrimaryKey' export const CONNECTION_NOT_FOUND_NAME = 'ConnectionNotFoundError' @@ -123,7 +123,7 @@ const connectOptions = async (genesisBlockHash: string): Promise ({ @@ -66,7 +66,7 @@ export abstract class Wallet { extendedKey: this.extendedKey, device: this.device, isHD: this.isHD, - startBlockNumberInLight: this.startBlockNumberInLight, + startBlockNumber: this.startBlockNumber, }) public fromJSON = () => { @@ -96,16 +96,16 @@ export abstract class Wallet { public update = ({ name, device, - startBlockNumberInLight, - }: Pick, 'name' | 'device' | 'startBlockNumberInLight'>) => { + startBlockNumber, + }: Pick, 'name' | 'device' | 'startBlockNumber'>) => { if (name) { this.name = name } if (device) { this.device = device } - if (startBlockNumberInLight) { - this.startBlockNumberInLight = startBlockNumberInLight + if (startBlockNumber) { + this.startBlockNumber = startBlockNumber } } @@ -153,7 +153,7 @@ export class FileKeystoreWallet extends Wallet { extendedKey: this.extendedKey, device: this.device, isHD: this.isHD, - startBlockNumberInLight: this.startBlockNumberInLight, + startBlockNumber: this.startBlockNumber, } } diff --git a/packages/neuron-wallet/tests/block-sync-renderer/light-connector.test.ts b/packages/neuron-wallet/tests/block-sync-renderer/light-connector.test.ts index 34f574438c..413af2a71c 100644 --- a/packages/neuron-wallet/tests/block-sync-renderer/light-connector.test.ts +++ b/packages/neuron-wallet/tests/block-sync-renderer/light-connector.test.ts @@ -371,7 +371,7 @@ describe('test light connector', () => { blake160: script.args, }) getWalletMinBlockNumberMock.mockResolvedValue({}) - walletGetAllMock.mockReturnValue([{ id: 'walletId', startBlockNumberInLight: '0xaa' }]) + walletGetAllMock.mockReturnValue([{ id: 'walletId', startBlockNumber: '0xaa' }]) const connect = new LightConnector([addressMeta], '') //@ts-ignore await connect.initSyncProgress()