diff --git a/packages/extension-base/src/background/KoniTypes.ts b/packages/extension-base/src/background/KoniTypes.ts index 7001afc849..04aa2ca8bf 100644 --- a/packages/extension-base/src/background/KoniTypes.ts +++ b/packages/extension-base/src/background/KoniTypes.ts @@ -967,6 +967,7 @@ export interface RequestAccountCreateHardwareV2 { address: string; addressOffset: number; genesisHash: string; + originGenesisHash: string; hardwareType: string; name: string; isAllowed?: boolean; @@ -977,6 +978,7 @@ export interface CreateHardwareAccountItem { address: string; addressOffset: number; genesisHash: string; + originGenesisHash: string; hardwareType: string; name: string; isEthereum: boolean; @@ -1415,10 +1417,16 @@ export interface LedgerNetwork { isGeneric: boolean; /** Use for evm account */ isEthereum: boolean; + /** Hide networks that are supported by the dot migration app */ + isHide?: boolean; /** Slip44 in the derivation path */ slip44: number; } +export interface MigrationLedgerNetwork extends Omit { + ss58_addr_type: number +} + /// Qr Sign // Parse Substrate diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index e3e102be25..afcc3e6042 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -2266,13 +2266,14 @@ export default class KoniExtension { genesisHash, hardwareType, isAllowed, - name }: RequestAccountCreateHardwareV2): Promise { + name, + originGenesisHash }: RequestAccountCreateHardwareV2): Promise { const key = keyring.addHardware(address, hardwareType, { accountIndex, addressOffset, genesisHash, name, - originGenesisHash: genesisHash + originGenesisHash }); const result = key.pair; @@ -2305,7 +2306,7 @@ export default class KoniExtension { const slugMap: Record = {}; for (const account of accounts) { - const { accountIndex, address, addressOffset, genesisHash, hardwareType, isEthereum, isGeneric, name } = account; + const { accountIndex, address, addressOffset, genesisHash, hardwareType, isEthereum, isGeneric, name, originGenesisHash } = account; let result: KeyringPair; @@ -2315,7 +2316,7 @@ export default class KoniExtension { accountIndex, addressOffset, genesisHash, - originGenesisHash: genesisHash, + originGenesisHash, isGeneric }; diff --git a/packages/extension-base/src/services/migration-service/scripts/MigrateLedgerAccountV2.ts b/packages/extension-base/src/services/migration-service/scripts/MigrateLedgerAccountV2.ts index 25849465b8..d1305c731c 100644 --- a/packages/extension-base/src/services/migration-service/scripts/MigrateLedgerAccountV2.ts +++ b/packages/extension-base/src/services/migration-service/scripts/MigrateLedgerAccountV2.ts @@ -16,7 +16,7 @@ export default class MigrateLedgerAccountV2 extends BaseMigrationJob { const store = new AccountsStore(); const update = (key: string, value: KeyringJson) => { - if (key.startsWith('account:') && value.meta && isString(value.meta?.originGenesisHash)) { + if (key.startsWith('account:') && value.meta && isString(value.meta?.genesisHash)) { const newValue = { ...value }; if (value.meta.isHardware) { @@ -25,11 +25,11 @@ export default class MigrateLedgerAccountV2 extends BaseMigrationJob { if (isEther) { newValue.meta.isGeneric = true; } else { - newValue.meta.isGeneric = !newValue.meta.originGenesisHash; + newValue.meta.isGeneric = !newValue.meta.genesisHash; } } - newValue.meta.availableGenesisHashes = [value.meta.originGenesisHash]; + newValue.meta.availableGenesisHashes = [value.meta.genesisHash]; store.set(key, newValue); } }; diff --git a/packages/extension-koni-ui/src/Popup/Account/ConnectLedger.tsx b/packages/extension-koni-ui/src/Popup/Account/ConnectLedger.tsx index 7d0c610a49..7907da1c06 100644 --- a/packages/extension-koni-ui/src/Popup/Account/ConnectLedger.tsx +++ b/packages/extension-koni-ui/src/Popup/Account/ConnectLedger.tsx @@ -1,10 +1,10 @@ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { LedgerNetwork } from '@subwallet/extension-base/background/KoniTypes'; +import { LedgerNetwork, MigrationLedgerNetwork } from '@subwallet/extension-base/background/KoniTypes'; import { reformatAddress } from '@subwallet/extension-base/utils'; import { AccountItemWithName, AccountWithNameSkeleton, BasicOnChangeFunction, ChainSelector, CloseIcon, DualLogo, Layout, PageWrapper } from '@subwallet/extension-koni-ui/components'; -import { ATTACH_ACCOUNT_MODAL } from '@subwallet/extension-koni-ui/constants'; +import { ATTACH_ACCOUNT_MODAL, SUBSTRATE_MIGRATION_KEY } from '@subwallet/extension-koni-ui/constants'; import { useAutoNavigateToCreatePassword, useCompleteCreateAccount, useDefaultNavigate, useGetSupportedLedger, useGoBackFromCreateAccount, useLedger } from '@subwallet/extension-koni-ui/hooks'; import { createAccountHardwareMultiple } from '@subwallet/extension-koni-ui/messaging'; import { RootState } from '@subwallet/extension-koni-ui/stores'; @@ -27,6 +27,10 @@ interface ImportLedgerItem { name: string; } +export const funcSortByName = (a: ChainItemType, b: ChainItemType) => { + return ((a?.name || '').toLowerCase() > (b?.name || '').toLowerCase()) ? 1 : -1; +}; + const LIMIT_PER_PAGE = 5; const FooterIcon = ( @@ -44,18 +48,26 @@ const Component: React.FC = (props: Props) => { const { t } = useTranslation(); const { goHome } = useDefaultNavigate(); - const supportedLedger = useGetSupportedLedger(); + const [supportedLedger, migrateSupportLedger] = useGetSupportedLedger(); const onComplete = useCompleteCreateAccount(); const onBack = useGoBackFromCreateAccount(ATTACH_ACCOUNT_MODAL); const { accounts } = useSelector((state: RootState) => state.accountState); - const networks = useMemo((): ChainItemType[] => supportedLedger.map((network) => ({ - name: !network.isGeneric ? network.networkName.replace(' network', '') : network.networkName, + const networks = useMemo((): ChainItemType[] => supportedLedger + .filter(({ isHide }) => !isHide) + .map((network) => ({ + name: !network.isGeneric ? network.networkName.replace(' network', '') : network.networkName, + slug: network.slug + })), [supportedLedger]); + + const networkMigrates = useMemo((): ChainItemType[] => migrateSupportLedger.map((network) => ({ + name: network.networkName.replace(' network', ''), slug: network.slug - })), [supportedLedger]); + })).sort(funcSortByName), [migrateSupportLedger]); const [chain, setChain] = useState(supportedLedger[0].slug); + const [chainMigrateMode, setChainMigrateMode] = useState(); const [ledgerAccounts, setLedgerAccounts] = useState>([]); const [firstStep, setFirstStep] = useState(ledgerAccounts.length === 0); const [page, setPage] = useState(0); @@ -67,9 +79,19 @@ const Component: React.FC = (props: Props) => { return supportedLedger.find((n) => n.slug === chain); }, [chain, supportedLedger]); + const selectedChainMigrateMode = useMemo((): MigrationLedgerNetwork | undefined => { + return migrateSupportLedger.find((n) => n.slug === chainMigrateMode); + }, [chainMigrateMode, migrateSupportLedger]); + const accountName = useMemo(() => selectedChain?.accountName || 'Unknown', [selectedChain]); - const { error, getAllAddress, isLoading, isLocked, ledger, refresh, warning } = useLedger(chain); + const accountMigrateNetworkName = useMemo(() => { + const selectedChain = migrateSupportLedger.find((n) => n.slug === chainMigrateMode); + + return chainMigrateMode && selectedChain ? `${selectedChain.accountName}` : ''; + }, [chainMigrateMode, migrateSupportLedger]); + + const { error, getAllAddress, isLoading, isLocked, ledger, refresh, warning } = useLedger(chain, true, false, false, selectedChainMigrateMode?.genesisHash); const onPreviousStep = useCallback(() => { setFirstStep(true); @@ -79,7 +101,19 @@ const Component: React.FC = (props: Props) => { const onChainChange: BasicOnChangeFunction = useCallback((event) => { const value = event.target.value; + if (value === SUBSTRATE_MIGRATION_KEY) { + setChainMigrateMode(networkMigrates[0].slug); + } else { + setChainMigrateMode(undefined); + } + setChain(value); + }, [networkMigrates]); + + const onMigrateChainChange: BasicOnChangeFunction = useCallback((event) => { + const value = event.target.value; + + setChainMigrateMode(value); }, []); const onLoadMore = useCallback(async () => { @@ -103,7 +137,7 @@ const Component: React.FC = (props: Props) => { (await getAllAddress(start, end)).forEach(({ address }, index) => { rs[start + index] = { accountIndex: start + index, - name: `Ledger ${accountName} ${start + index + 1}`, + name: `Ledger ${accountMigrateNetworkName} ${accountMigrateNetworkName ? `(${accountName})` : accountName} ${start + index + 1}`, address: address }; }); @@ -132,7 +166,7 @@ const Component: React.FC = (props: Props) => { }); loadingFlag.current = false; - }, [page, getAllAddress, accountName, refresh]); + }, [page, getAllAddress, accountName, accountMigrateNetworkName, refresh]); const onNextStep = useCallback(() => { setFirstStep(false); @@ -173,12 +207,13 @@ const Component: React.FC = (props: Props) => { const selected = !!selectedAccounts.find((it) => it.address === item.address); const originAddress = reformatAddress(item.address, 42); - const disabled = !!accounts.find((acc) => acc.address === originAddress && acc.genesisHash === selectedChain?.genesisHash); + const existedAccount = accounts.find((acc) => acc.address === originAddress && acc.genesisHash === selectedChain?.genesisHash); + const disabled = !!existedAccount; return ( = (props: Props) => { /> ); }; - }, [accounts, onClickItem, selectedChain?.genesisHash]); + }, [accounts, chainMigrateMode, onClickItem, selectedChain?.genesisHash]); const onSubmit = useCallback(() => { if (!selectedAccounts.length || !selectedChain) { @@ -205,6 +240,7 @@ const Component: React.FC = (props: Props) => { address: item.address, addressOffset: 0, // don't change genesisHash: selectedChain.genesisHash, + originGenesisHash: selectedChainMigrateMode?.genesisHash || selectedChain.genesisHash, hardwareType: 'ledger', name: item.name, isEthereum: selectedChain.isEthereum, @@ -221,13 +257,13 @@ const Component: React.FC = (props: Props) => { setIsSubmitting(false); }); }, 300); - }, [selectedAccounts, selectedChain, onComplete]); + }, [selectedAccounts, selectedChain, selectedChainMigrateMode?.genesisHash, onComplete]); useEffect(() => { setSelectedAccounts([]); setLedgerAccounts([]); setPage(0); - }, [chain]); + }, [chain, chainMigrateMode]); const isConnected = !isLocked && !isLoading && !!ledger; @@ -279,11 +315,22 @@ const Component: React.FC = (props: Props) => { + { + !!chainMigrateMode && + }