Unverified Commit 95de64e3 authored by Hanwen Cheng's avatar Hanwen Cheng Committed by GitHub
Browse files

fix: missing accounts on v4.2 (#607)

* fix path list method

* strict signed message and signed tx screen rendering
parent e3a60ba9
Pipeline #91448 failed with stages
in 3 minutes and 48 seconds
......@@ -40,6 +40,7 @@ const CompatibleCard = ({
networkKey={account.networkKey || ''}
/>
) : (
//Substrate tx do not need to render recipient
<PathCard
identity={accountsStore.getIdentityByAccountId(account.accountId)!}
path={account.path}
......
......@@ -274,6 +274,14 @@ export const UNKNOWN_NETWORK: {
[key: string]: UnknownNetworkParams;
} = Object.freeze(unknownNetworkBase);
const substrateNetworkMetas = Object.values({
...SUBSTRATE_NETWORK_LIST,
...UNKNOWN_NETWORK
});
export const PATH_IDS_LIST = substrateNetworkMetas.map(
(meta: UnknownNetworkParams | SubstrateNetworkParams) => meta.pathId
);
export const NETWORK_LIST: { [key: string]: NetworkParams } = Object.freeze(
Object.assign(
{},
......
......@@ -14,8 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from 'react';
import { BackHandler, ScrollView } from 'react-native';
import React, { ReactElement, useState } from 'react';
import { BackHandler, FlatList } from 'react-native';
import { useFocusEffect } from '@react-navigation/native';
import { NetworkCard } from 'components/AccountCard';
......@@ -23,7 +23,6 @@ import { SafeAreaViewContainer } from 'components/SafeAreaContainer';
import ScreenHeading, { IdentityHeading } from 'components/ScreenHeading';
import {
NETWORK_LIST,
NetworkProtocols,
SubstrateNetworkKeys,
UnknownNetworkKeys
} from 'constants/networkSpecs';
......@@ -32,17 +31,12 @@ import colors from 'styles/colors';
import {
isEthereumNetworkParams,
isSubstrateNetworkParams,
isUnknownNetworkParams,
NetworkParams,
SubstrateNetworkParams
} from 'types/networkSpecsTypes';
import { NavigationAccountIdentityProps } from 'types/props';
import { alertPathDerivationError } from 'utils/alertUtils';
import {
getExistedNetworkKeys,
getIdentityName,
getPathsWithSubstrateNetworkKey
} from 'utils/identitiesUtils';
import { getExistedNetworkKeys, getIdentityName } from 'utils/identitiesUtils';
import {
navigateToPathDerivation,
navigateToPathDetails,
......@@ -196,33 +190,13 @@ export default function NetworkSelector({
networkKey: string,
networkParams: NetworkParams
): Promise<void> => {
if (isNew) {
if (isNew || shouldShowMoreNetworks) {
if (isSubstrateNetworkParams(networkParams)) {
await deriveSubstrateNetworkRootPath(networkKey, networkParams);
} else {
await deriveEthereumAccount(networkKey);
}
} else {
const paths = Array.from(currentIdentity.meta.keys());
if (
isSubstrateNetworkParams(networkParams) ||
isUnknownNetworkParams(networkParams)
) {
const listedPaths = getPathsWithSubstrateNetworkKey(
currentIdentity,
networkKey
);
if (listedPaths.length === 0 && isSubstrateNetworkParams(networkParams))
return await deriveSubstrateNetworkRootPath(
networkKey,
networkParams
);
} else if (
networkParams.protocol === NetworkProtocols.ETHEREUM &&
!paths.includes(networkKey)
) {
return await deriveEthereumAccount(networkKey);
}
navigation.navigate('PathsList', { networkKey });
}
};
......@@ -231,28 +205,39 @@ export default function NetworkSelector({
const networkList = Object.entries(NETWORK_LIST).filter(filterNetworkKeys);
networkList.sort(sortNetworkKeys);
const renderNetwork = ({
item
}: {
item: [string, NetworkParams];
}): ReactElement => {
const [networkKey, networkParams] = item;
const networkIndexSuffix = isEthereumNetworkParams(networkParams)
? networkParams.ethereumChainId
: networkParams.pathId;
return (
<NetworkCard
key={networkKey}
testID={testIDs.Main.networkButton + networkIndexSuffix}
networkKey={networkKey}
onPress={(): Promise<void> =>
onNetworkChosen(networkKey, networkParams)
}
title={networkParams.title}
/>
);
};
return (
<SafeAreaViewContainer>
{renderScreenHeading()}
<ScrollView bounces={false} testID={testIDs.Main.chooserScreen}>
{networkList.map(([networkKey, networkParams]) => {
const networkIndexSuffix = isEthereumNetworkParams(networkParams)
? networkParams.ethereumChainId
: networkParams.pathId;
return (
<NetworkCard
key={networkKey}
testID={testIDs.Main.networkButton + networkIndexSuffix}
networkKey={networkKey}
onPress={(): Promise<void> =>
onNetworkChosen(networkKey, networkParams)
}
title={networkParams.title}
/>
);
})}
{renderAddButton()}
</ScrollView>
<FlatList
bounces={false}
data={networkList}
keyExtractor={(item: [string, NetworkParams]): string => item[0]}
renderItem={renderNetwork}
testID={testIDs.Main.chooserScreen}
ListFooterComponent={renderAddButton}
/>
</SafeAreaViewContainer>
);
}
......@@ -24,6 +24,7 @@ import PayloadDetailsCard from 'modules/sign/components/PayloadDetailsCard';
import { NETWORK_LIST } from 'constants/networkSpecs';
import { SafeAreaScrollViewContainer } from 'components/SafeAreaContainer';
import testIDs from 'e2e/testIDs';
import { FoundAccount } from 'types/identityTypes';
import { isEthereumNetworkParams } from 'types/networkSpecsTypes';
import { NavigationAccountScannerProps } from 'types/props';
import QrView from 'components/QrView';
......@@ -31,17 +32,32 @@ import { withAccountAndScannerStore } from 'utils/HOC';
import styles from 'modules/sign/styles';
import MessageDetailsCard from 'modules/sign/components/MessageDetailsCard';
function SignedMessage({
interface Props extends NavigationAccountScannerProps<'SignedMessage'> {
sender: FoundAccount;
message: string;
}
function SignedMessage(
props: NavigationAccountScannerProps<'SignedMessage'>
): React.ReactElement {
const { scannerStore } = props;
const sender = scannerStore.getSender();
const message = scannerStore.getMessage();
if (sender === null || message === null) return <View />;
return <SignedMessageView sender={sender} message={message} {...props} />;
}
function SignedMessageView({
sender,
message,
accounts,
scannerStore
}: NavigationAccountScannerProps<'SignedMessage'>): React.ReactElement {
}: Props): React.ReactElement {
const data = scannerStore.getSignedTxData();
const isHash = scannerStore.getIsHash();
const message = scannerStore.getMessage()!;
const prehash = scannerStore.getPrehashPayload();
const dataToSign = scannerStore.getDataToSign()!;
const dataToSign = scannerStore.getDataToSign();
const sender = scannerStore.getSender()!;
const senderNetworkParams = NETWORK_LIST[sender.networkKey];
const isEthereum = isEthereumNetworkParams(senderNetworkParams);
......
......@@ -21,6 +21,7 @@ import strings from 'modules/sign/strings';
import { SafeAreaScrollViewContainer } from 'components/SafeAreaContainer';
import { NETWORK_LIST } from 'constants/networkSpecs';
import testIDs from 'e2e/testIDs';
import { FoundAccount } from 'types/identityTypes';
import { isEthereumNetworkParams } from 'types/networkSpecsTypes';
import { NavigationAccountScannerProps } from 'types/props';
import PayloadDetailsCard from 'modules/sign/components/PayloadDetailsCard';
......@@ -32,16 +33,30 @@ import CompatibleCard from 'components/CompatibleCard';
import { Transaction } from 'utils/transaction';
import styles from 'modules/sign/styles';
function SignedTx({
scannerStore,
accounts
}: NavigationAccountScannerProps<'SignedTx'>): React.ReactElement {
function SignedTx(
props: NavigationAccountScannerProps<'SignedTx'>
): React.ReactElement {
const { scannerStore } = props;
const recipient = scannerStore.getRecipient();
const sender = scannerStore.getSender();
if (sender === null || recipient === null) return <View />;
return <SignedTxView sender={sender} recipient={recipient} {...props} />;
}
interface Props extends NavigationAccountScannerProps<'SignedTx'> {
sender: FoundAccount;
recipient: FoundAccount;
}
function SignedTxView({
sender,
recipient,
accounts,
scannerStore
}: Props): React.ReactElement {
const data = scannerStore.getSignedTxData();
const recipient = scannerStore.getRecipient()!;
const prehash = scannerStore.getPrehashPayload();
const tx = scannerStore.getTx();
const sender = scannerStore.getSender()!;
const senderNetworkParams = NETWORK_LIST[sender.networkKey];
const isEthereum = isEthereumNetworkParams(senderNetworkParams);
const { value, gas, gasPrice } = tx as Transaction;
......
......@@ -40,7 +40,7 @@ function getSeedRef(
seedRefs: Map<string, SeedRefClass>
): SeedRefClass | undefined {
if (seedRefs.has(encryptedSeed)) {
return seedRefs.get(encryptedSeed)!;
return seedRefs.get(encryptedSeed);
}
}
......
......@@ -22,9 +22,11 @@ import { generateAccountId } from './account';
import { TryCreateFunc } from 'utils/seedRefHooks';
import {
NETWORK_LIST,
PATH_IDS_LIST,
SUBSTRATE_NETWORK_LIST,
SubstrateNetworkKeys,
UnknownNetworkKeys
UnknownNetworkKeys,
unknownNetworkPathId
} from 'constants/networkSpecs';
import {
Account,
......@@ -56,10 +58,15 @@ export function isLegacyFoundAccount(
return foundAccount.isLegacy;
}
export const extractPathId = (path: string): string | null => {
export const extractPathId = (path: string): string => {
const matchNetworkPath = path.match(pathsRegex.networkPath);
if (!matchNetworkPath) return null;
return removeSlash(matchNetworkPath[0]);
if (matchNetworkPath && matchNetworkPath[0]) {
const targetPathId = removeSlash(matchNetworkPath[0]);
if (PATH_IDS_LIST.includes(targetPathId)) {
return targetPathId;
}
}
return unknownNetworkPathId;
};
export const extractSubPathName = (path: string): string => {
......@@ -155,9 +162,7 @@ export const getPathsWithSubstrateNetworkKey = (
networkKey: string
): string[] => {
const pathEntries = Array.from(identity.meta.entries());
const isUnknownNetworkKey = networkKey === 'unknown';
const targetPathId = SUBSTRATE_NETWORK_LIST[networkKey]?.pathId;
const knownPathIds = Object.values(SUBSTRATE_NETWORK_LIST).map(v => v.pathId);
const pathReducer = (
groupedPaths: string[],
[path, pathMeta]: [string, AccountMeta]
......@@ -170,14 +175,9 @@ export const getPathsWithSubstrateNetworkKey = (
pathId = extractPathId(path);
}
if (!isUnknownNetworkKey) {
if (pathId === targetPathId) {
groupedPaths.push(path);
}
} else {
if (pathId && !knownPathIds.includes(pathId)) {
groupedPaths.push(path);
}
if (pathId === targetPathId) {
groupedPaths.push(path);
return groupedPaths;
}
return groupedPaths;
};
......@@ -205,10 +205,10 @@ export const getNetworkKeyByPath = (
pathMeta: AccountMeta
): string => {
if (!isSubstratePath(path) && NETWORK_LIST.hasOwnProperty(path)) {
//It is a ethereum path
return path;
}
const pathId = pathMeta.networkPathId || extractPathId(path);
if (!pathId) return UnknownNetworkKeys.UNKNOWN;
return getNetworkKeyByPathId(pathId);
};
......
......@@ -19,6 +19,7 @@ import {
getExistedNetworkKeys,
getNetworkKeyByPath,
getPathName,
getPathsWithSubstrateNetworkKey,
groupPaths,
serializeIdentities
} from 'utils/identitiesUtils';
......@@ -258,4 +259,30 @@ describe('IdentitiesUtils', () => {
);
expect(getNetworkKeyByPathTest('1')).toEqual(EthereumNetworkKeys.FRONTIER);
});
it('group path under their network correctly, has no missing accounts', () => {
const mockIdentity = testIdentities[0];
const existedNetworks = getExistedNetworkKeys(mockIdentity);
const existedAccounts = mockIdentity.meta.size;
const allListedAccounts = existedNetworks.reduce(
(acc: string[], networkKey: string) => {
if (Object.values(EthereumNetworkKeys).includes(networkKey)) {
//Get ethereum account into list
const accountMeta = mockIdentity.meta.get(networkKey);
if (accountMeta === undefined) return acc;
acc.push(networkKey);
return acc;
} else {
const networkAccounts = getPathsWithSubstrateNetworkKey(
mockIdentity,
networkKey
);
return acc.concat(networkAccounts);
}
},
[]
);
expect(existedAccounts).toEqual(allListedAccounts.length);
});
});
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment