Unverified Commit 1b6c234c authored by Hanwen Cheng's avatar Hanwen Cheng Committed by GitHub

fix: erros on unknown network. show Identity on SignedTx/SignedMessage screen (#673)

* ui: add identity on SignedTx and SignedMessage

* fix error on signing with unknown network

* add backward compatibility for legacy accounts

* fix: icon display
parent 28ce011d
Pipeline #103741 failed with stages
in 3 minutes and 21 seconds
......@@ -23,8 +23,8 @@ import Address from './Address';
import TouchableItem from './TouchableItem';
import AccountPrefixedTitle from './AccountPrefixedTitle';
import { getNetworkParams } from 'utils/identitiesUtils';
import Separator from 'components/Separator';
import { NETWORK_LIST, NetworkProtocols } from 'constants/networkSpecs';
import fontStyles from 'styles/fontStyles';
import colors from 'styles/colors';
import { ButtonListener } from 'types/props';
......@@ -66,10 +66,7 @@ export function NetworkCard({
testID?: string;
title: string;
}): ReactElement {
const network =
networkKey !== undefined
? NETWORK_LIST[networkKey]
: NETWORK_LIST[NetworkProtocols.UNKNOWN];
const networkParams = getNetworkParams(networkKey);
const isDisabled = onPress === undefined;
return (
<TouchableItem testID={testID} disabled={isDisabled} onPress={onPress}>
......@@ -87,12 +84,16 @@ export function NetworkCard({
<Icon name="add" color={colors.text.main} size={30} />
</View>
) : (
<AccountIcon address={''} network={network} style={styles.icon} />
<AccountIcon
address={''}
network={networkParams}
style={styles.icon}
/>
)}
<View style={styles.desc}>
<AccountPrefixedTitle title={title} />
</View>
<NetworkFooter color={networkColor ?? network.color} />
<NetworkFooter color={networkColor ?? networkParams.color} />
</View>
</TouchableItem>
);
......@@ -122,10 +123,7 @@ export default function AccountCard({
const defaultTitle = 'No name';
const displayTitle = title.length > 0 ? title : defaultTitle;
const seedTypeDisplay = seedType || '';
const network =
networkKey !== undefined
? NETWORK_LIST[networkKey]
: NETWORK_LIST[NetworkProtocols.UNKNOWN];
const network = getNetworkParams(networkKey);
return (
<TouchableItem
......
......@@ -66,7 +66,11 @@ export default function AccountIcon(props: {
</View>
);
}
if (protocol === NetworkProtocols.SUBSTRATE) {
if (protocol === NetworkProtocols.ETHEREUM) {
return (
<Image source={{ uri: ethereumIconUri }} style={style as ImageStyle} />
);
} else if (address !== '') {
let iconSize;
if (typeof style?.width === 'string') {
const parseIconSize = parseInt(style.width, 10);
......@@ -75,12 +79,7 @@ export default function AccountIcon(props: {
iconSize = style?.width;
}
return <Identicon value={address} size={iconSize || 40} />;
} else if (protocol === NetworkProtocols.ETHEREUM && ethereumIconUri) {
return (
<Image source={{ uri: ethereumIconUri }} style={style as ImageStyle} />
);
} else {
// if there's no protocol or it's unknown we return a warning
return (
<MaterialIcon color={colors.signal.error} name={'error'} size={44} />
);
......
......@@ -28,7 +28,7 @@ export default function AccountPrefixedTitle({
titlePrefix?: string;
}): ReactElement {
return (
<View style={{ flexDirection: 'row' }}>
<View style={{ flexDirection: 'column' }}>
{titlePrefix && (
<Text numberOfLines={1} style={[fontStyles.t_codeS, styles.text]}>
{titlePrefix}
......@@ -43,7 +43,6 @@ export default function AccountPrefixedTitle({
const styles = StyleSheet.create({
text: {
alignSelf: 'flex-end',
color: colors.signal.main,
marginBottom: 1,
marginRight: 4
......
......@@ -21,7 +21,11 @@ import AccountCard from './AccountCard';
import PathCard from './PathCard';
import { AccountsContextState } from 'stores/AccountsContext';
import { FoundAccount } from 'types/identityTypes';
import {
FoundAccount,
FoundIdentityAccount,
FoundLegacyAccount
} from 'types/identityTypes';
import { isLegacyFoundAccount } from 'utils/identitiesUtils';
const CompatibleCard = ({
......@@ -32,22 +36,37 @@ const CompatibleCard = ({
account: FoundAccount;
accountsStore: AccountsContextState;
titlePrefix?: string;
}): React.ReactElement =>
isLegacyFoundAccount(account) || account.isLegacy === undefined ? (
}): React.ReactElement => {
const renderLegacyAccountCard = (
legacyAccount: FoundLegacyAccount
): React.ReactElement => (
<AccountCard
title={account.name}
address={account.address}
networkKey={account.networkKey || ''}
/>
) : (
//Substrate tx do not need to render recipient
<PathCard
identity={accountsStore.getIdentityByAccountId(account.accountId)!}
path={account.path}
titlePrefix={titlePrefix}
title={legacyAccount.name}
address={legacyAccount.address}
networkKey={legacyAccount.networkKey || ''}
/>
);
const renderIdentityPathCard = (
identityAccount: FoundIdentityAccount
): React.ReactElement => {
const identity = accountsStore.getIdentityByAccountId(
identityAccount.accountId
)!;
return (
<PathCard
identity={identity}
path={identityAccount.path}
titlePrefix={titlePrefix + identity.name}
/>
);
};
return isLegacyFoundAccount(account) || account.isLegacy === undefined
? renderLegacyAccountCard(account)
: renderIdentityPathCard(account);
};
CompatibleCard.propTypes = {
account: PropTypes.object.isRequired,
accountsStore: PropTypes.object.isRequired,
......
......@@ -246,6 +246,7 @@ const styles = StyleSheet.create({
width: 40
},
row: {
alignItems: 'flex-end',
flexDirection: 'row'
}
});
......@@ -46,9 +46,9 @@ export function UnknownAccountWarning({
</Text>
) : (
<Text style={styles.warningText}>
This account wasn't retrieved successfully. This could be because its
network isn't supported, or you upgraded Parity Signer without wiping
your device and this account couldn't be migrated.
This account wasn't retrieved successfully. This could be because
network's genesisHash is changed, or you upgraded Parity Signer
without wiping your device and this account couldn't be migrated.
{'\n'}
{'\n'}
To be able to use this account you need to:
......
......@@ -14,8 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
// @flow
import {
SUBSTRATE_NETWORK_LIST,
SubstrateNetworkKeys,
......
......@@ -19,7 +19,6 @@ import { Text, View } from 'react-native';
import strings from 'modules/sign/strings';
import { SafeAreaScrollViewContainer } from 'components/SafeAreaContainer';
import { NETWORK_LIST } from 'constants/networkSpecs';
import testIDs from 'e2e/testIDs';
import { AccountsContext } from 'stores/AccountsContext';
import { ScannerContext } from 'stores/ScannerContext';
......@@ -30,6 +29,7 @@ import TxDetailsCard from 'modules/sign/components/TxDetailsCard';
import QrView from 'components/QrView';
import fontStyles from 'styles/fontStyles';
import CompatibleCard from 'components/CompatibleCard';
import { getNetworkParams } from 'utils/identitiesUtils';
import { Transaction } from 'utils/transaction';
import styles from 'modules/sign/styles';
import Separator from 'components/Separator';
......@@ -64,7 +64,7 @@ function SignedTxView({
}: Props): React.ReactElement {
const accountsStore = useContext(AccountsContext);
const { signedData, tx } = scannerStore.state;
const senderNetworkParams = NETWORK_LIST[sender.networkKey];
const senderNetworkParams = getNetworkParams(sender.networkKey);
const isEthereum = isEthereumNetworkParams(senderNetworkParams);
const { value, gas, gasPrice } = tx as Transaction;
......
......@@ -17,7 +17,6 @@ import { useNavigation } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
import { useContext } from 'react';
import { NETWORK_LIST } from 'constants/networkSpecs';
import strings from 'modules/sign/strings';
import { AccountsContext } from 'stores/AccountsContext';
import { ScannerContext } from 'stores/ScannerContext';
......@@ -39,7 +38,7 @@ import {
isJsonString,
rawDataToU8A
} from 'utils/decoders';
import { getIdentityFromSender } from 'utils/identitiesUtils';
import { getIdentityFromSender, getNetworkParams } from 'utils/identitiesUtils';
import { SeedRefClass } from 'utils/native';
import {
unlockSeedPhrase,
......@@ -108,7 +107,7 @@ export function useProcessBarCode(
sender: FoundIdentityAccount,
qrInfo: QrInfo
): Promise<void> {
const senderNetworkParams = NETWORK_LIST[sender.networkKey];
const senderNetworkParams = getNetworkParams(sender.networkKey);
const isEthereum = isEthereumNetworkParams(senderNetworkParams);
// 1. check if sender existed
......
......@@ -18,7 +18,7 @@ import React, { useContext } from 'react';
import { ScrollView, StyleSheet, Text, View } from 'react-native';
import { SafeAreaViewContainer } from 'components/SafeAreaContainer';
import { NETWORK_LIST, NetworkProtocols } from 'constants/networkSpecs';
import { NetworkProtocols } from 'constants/networkSpecs';
import { AccountsContext } from 'stores/AccountsContext';
import { AlertStateContext } from 'stores/alertContext';
import colors from 'styles/colors';
......@@ -26,6 +26,7 @@ import AccountCard from 'components/AccountCard';
import QrView from 'components/QrView';
import PopupMenu from 'components/PopupMenu';
import { alertDeleteLegacyAccount } from 'utils/alertUtils';
import { getNetworkParams } from 'utils/identitiesUtils';
import {
navigateToLandingPage,
navigateToLegacyAccountList
......@@ -46,11 +47,9 @@ export default function AccountDetails({
if (!account) return <View />;
const protocol =
(account.networkKey &&
NETWORK_LIST[account.networkKey] &&
NETWORK_LIST[account.networkKey].protocol) ||
NetworkProtocols.UNKNOWN;
const network = getNetworkParams(account.networkKey);
const protocol = network.protocol;
const onDelete = (): void => {
alertDeleteLegacyAccount(
......@@ -79,13 +78,9 @@ export default function AccountDetails({
return (
<SafeAreaViewContainer>
<ScrollView contentContainerStyle={styles.scrollBody}>
<ScrollView style={styles.scrollBody} bounces={false}>
<View style={styles.header}>
<AccountIcon
address={''}
network={NETWORK_LIST[account.networkKey]}
style={styles.icon}
/>
<AccountIcon address={''} network={network} style={styles.icon} />
<Text style={fontStyles.h2}>Public Address</Text>
<View style={styles.menuView}>
<PopupMenu
......@@ -113,15 +108,10 @@ export default function AccountDetails({
title={account.name}
/>
<View>
{protocol !== NetworkProtocols.UNKNOWN ? (
<QrView
data={
account.name ? `${selectedKey}:${account.name}` : selectedKey
}
/>
) : (
<UnknownAccountWarning />
)}
<QrView
data={account.name ? `${selectedKey}:${account.name}` : selectedKey}
/>
{protocol === NetworkProtocols.UNKNOWN && <UnknownAccountWarning />}
</View>
</ScrollView>
<QrScannerTab />
......@@ -153,7 +143,6 @@ const styles = StyleSheet.create({
scrollBody: {
alignContent: 'flex-start',
flex: 1,
paddingBottom: 40,
paddingTop: 8
}
});
......@@ -18,7 +18,7 @@ import React, { useContext, useEffect } from 'react';
import { AppState, AppStateStatus, StyleSheet, Text, View } from 'react-native';
import { SafeAreaScrollViewContainer } from 'components/SafeAreaContainer';
import { NetworkProtocols, NETWORK_LIST } from 'constants/networkSpecs';
import { NetworkProtocols } from 'constants/networkSpecs';
import { AccountsContext } from 'stores/AccountsContext';
import { AlertStateContext } from 'stores/alertContext';
import { UnlockedAccount } from 'types/identityTypes';
......@@ -32,6 +32,7 @@ import ScreenHeading from 'components/ScreenHeading';
import TouchableItem from 'components/TouchableItem';
import DerivationPasswordVerify from 'components/DerivationPasswordVerify';
import { alertBackupDone, alertCopyBackupPhrase } from 'utils/alertUtils';
import { getNetworkParams } from 'utils/identitiesUtils';
function LegacyAccountBackup({
navigation,
......@@ -68,9 +69,7 @@ function LegacyAccountBackup({
seed = '',
seedPhrase = ''
} = isNew ? newAccount : (accountsStore.getSelected() as UnlockedAccount);
const protocol =
(NETWORK_LIST[networkKey] && NETWORK_LIST[networkKey].protocol) ||
NetworkProtocols.UNKNOWN;
const protocol = getNetworkParams(networkKey).protocol;
return (
<SafeAreaScrollViewContainer style={styles.body}>
......
......@@ -277,7 +277,6 @@ export function useAccountContext(): AccountsContextState {
): Promise<boolean> {
const { accounts } = state;
const account = accounts.get(accountKey);
if (!accountKey || !account || !account.encryptedSeed) {
return false;
}
......
......@@ -26,8 +26,9 @@ import {
import React, { useReducer } from 'react';
import { AccountsContextState } from 'stores/AccountsContext';
import { NETWORK_LIST, NetworkProtocols } from 'constants/networkSpecs';
import { NETWORK_LIST } from 'constants/networkSpecs';
import { Account, FoundAccount } from 'types/identityTypes';
import { isEthereumNetworkParams } from 'types/networkSpecsTypes';
import {
CompletedParsedData,
EthereumParsedData,
......@@ -47,6 +48,7 @@ import {
constructDataFromBytes,
encodeNumber
} from 'utils/decoders';
import { getNetworkParams } from 'utils/identitiesUtils';
import {
brainWalletSign,
decryptData,
......@@ -313,7 +315,7 @@ export function useScannerContext(): ScannerContextState {
networkKey
});
const networkTitle = NETWORK_LIST[networkKey].title;
const networkTitle = getNetworkParams(networkKey).title;
if (!sender) {
throw new Error(
......@@ -455,8 +457,8 @@ export function useScannerContext(): ScannerContextState {
const { sender, dataToSign, isHash } = state;
if (!sender || !sender.encryptedSeed)
throw new Error('Signing Error: sender could not be found.');
const isEthereum =
NETWORK_LIST[sender.networkKey].protocol === NetworkProtocols.ETHEREUM;
const networkParams = getNetworkParams(sender.networkKey);
const isEthereum = isEthereumNetworkParams(networkParams);
const seed = await decryptData(sender.encryptedSeed, pin);
let signedData;
if (isEthereum) {
......@@ -499,7 +501,6 @@ export function useScannerContext(): ScannerContextState {
setState({
...DEFAULT_STATE
});
clearMultipartProgress();
}
return {
......
......@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { NETWORK_LIST, SubstrateNetworkKeys } from 'constants/networkSpecs';
import { SubstrateNetworkKeys } from 'constants/networkSpecs';
import { UnlockedAccount } from 'types/identityTypes';
import {
EthereumNetworkParams,
......@@ -22,6 +22,7 @@ import {
isUnknownNetworkParams
} from 'types/networkSpecsTypes';
import { ValidSeed } from 'types/utilTypes';
import { getNetworkParams } from 'utils/identitiesUtils';
export function generateAccountId({
address,
......@@ -30,25 +31,20 @@ export function generateAccountId({
address: string;
networkKey: string;
}): string {
if (
typeof address !== 'string' ||
address.length === 0 ||
!networkKey ||
!NETWORK_LIST[networkKey]
) {
if (typeof address !== 'string' || address.length === 0 || !networkKey) {
throw new Error(
"Couldn't create an accountId. Address or networkKey missing, or network key was invalid."
);
}
const networkParams = NETWORK_LIST[networkKey];
const networkParams = getNetworkParams(networkKey);
const { protocol } = networkParams;
if (isSubstrateNetworkParams(networkParams)) {
const { genesisHash } = networkParams;
return `${protocol}:${address}:${genesisHash ?? ''}`;
} else if (isUnknownNetworkParams(networkParams)) {
return `substrate:${address}`;
return `substrate:${address}:${networkKey ?? ''}`;
} else {
const { ethereumChainId } = networkParams as EthereumNetworkParams;
return `${protocol}:0x${address}@${ethereumChainId}`;
......
......@@ -19,6 +19,7 @@ import { decryptData, substrateAddress } from './native';
import { constructSURI, parseSURI } from './suri';
import { generateAccountId } from './account';
import { NetworkParams } from 'types/networkSpecsTypes';
import { TryCreateFunc } from 'utils/seedRefHooks';
import {
NETWORK_LIST,
......@@ -295,6 +296,15 @@ export const verifyPassword = async (
return address === accountMeta?.address;
};
export const getNetworkParams = (
networkKey: string | undefined
): NetworkParams => {
if (networkKey === undefined) return NETWORK_LIST[UnknownNetworkKeys.UNKNOWN];
return NETWORK_LIST.hasOwnProperty(networkKey)
? NETWORK_LIST[networkKey]
: NETWORK_LIST[UnknownNetworkKeys.UNKNOWN];
};
export const getExistedNetworkKeys = (identity: Identity): string[] => {
const pathEntries = Array.from(identity.meta.entries());
const networkKeysSet = pathEntries.reduce(
......
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