Skip to content

Commit 0269bc4

Browse files
committed
[Issue-4365] feat(ledger): support new flow to manager any specific account
1 parent 2874b4d commit 0269bc4

File tree

18 files changed

+93
-92
lines changed

18 files changed

+93
-92
lines changed

packages/extension-base/src/core/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import { _ChainInfo } from '@subwallet/chain-list/types';
55
import { AccountJson } from '@subwallet/extension-base/types';
66

7-
export type LedgerMustCheckType = 'polkadot' | 'migration' | 'unnecessary';
7+
export type LedgerMustCheckType = 'polkadot' | 'migration' | 'polkadot_ecdsa' | 'unnecessary';
88

99
export enum ValidationCondition {
1010
IS_NOT_NULL = 'IS_NOT_NULL',

packages/extension-base/src/core/utils.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,15 @@ export function getMaxBigInt (a: bigint, b: bigint): bigint {
3232
}
3333

3434
export function ledgerMustCheckNetwork (account: AccountJson | null): LedgerMustCheckType {
35-
if (account && account.isHardware && account.isGeneric && !isEthereumAddress(account.address)) {
36-
return account.originGenesisHash ? 'migration' : 'polkadot';
37-
} else {
38-
return 'unnecessary';
35+
if (account && account.isHardware && account.isGeneric) {
36+
if (!isEthereumAddress(account.address)) {
37+
return account.originGenesisHash ? 'migration' : 'polkadot';
38+
} else if (account.isSubstrateECDSA) {
39+
return 'polkadot_ecdsa';
40+
}
3941
}
42+
43+
return 'unnecessary';
4044
}
4145

4246
// --- recipient address validation --- //
@@ -137,23 +141,21 @@ export function _isSupportLedgerAccount (validateRecipientParams: ValidateRecipi
137141

138142
if (account?.isHardware) {
139143
if (!account.isGeneric) {
140-
if (account.isSubstrateECDSA) {
141-
if (!destChainInfo.substrateInfo || !destChainInfo.evmInfo) {
142-
return 'Your Ledger account is not supported by {{network}} network.'.replace('{{network}}', destChainInfo?.name || 'Unknown');
143-
}
144-
} else {
145-
// For ledger legacy
146-
const availableGen: string[] = account.availableGenesisHashes || [];
147-
const destChainName = destChainInfo?.name || 'Unknown';
144+
// For ledger legacy
145+
const availableGen: string[] = account.availableGenesisHashes || [];
146+
const destChainName = destChainInfo?.name || 'Unknown';
148147

149-
if (!availableGen.includes(destChainInfo?.substrateInfo?.genesisHash || '')) {
150-
return 'Your Ledger account is not supported by {{network}} network.'.replace('{{network}}', destChainName);
151-
}
148+
if (!availableGen.includes(destChainInfo?.substrateInfo?.genesisHash || '')) {
149+
return 'Your Ledger account is not supported by {{network}} network.'.replace('{{network}}', destChainName);
152150
}
153151
} else {
154152
// For ledger generic
155153
const ledgerCheck = ledgerMustCheckNetwork(account);
156154

155+
if (ledgerCheck === 'polkadot_ecdsa' && (!destChainInfo.substrateInfo || !destChainInfo.evmInfo)) {
156+
return 'Ledger ECDSA address is not supported for this transfer';
157+
}
158+
157159
if (ledgerCheck !== 'unnecessary' && !allowLedgerGenerics.includes(destChainInfo.slug)) {
158160
return `Ledger ${ledgerCheck === 'polkadot' ? 'Polkadot' : 'Migration'} address is not supported for this transfer`;
159161
}

packages/extension-base/src/koni/background/handlers/Tabs.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ function transformAccountsV2 (accounts: SubjectInfo, anyType = false, authInfo?:
6969
cardano: CardanoKeypairTypes
7070
};
7171

72+
// This condition ensures that the substrate account with evm format address is can be used in Substrate dApps
7273
const subCondition = (authType: AccountAuthType) => authType === 'substrate' && json.meta.isSubstrateECDSA;
7374
const isValidTypes = accountAuthTypes.some((authType) => validTypes[authType]?.includes(type) || subCondition(authType));
7475

@@ -81,6 +82,11 @@ function transformAccountsV2 (accounts: SubjectInfo, anyType = false, authInfo?:
8182
return false;
8283
}
8384

85+
// If the user only wants to connect to EVM, we don't return Substrate ECDSA accounts
86+
if (type === 'ethereum' && json.meta.isSubstrateECDSA && accountAuthTypes.length === 1 && accountAuthTypes[0] === 'evm') {
87+
return false;
88+
}
89+
8490
return true;
8591
} else {
8692
return true;

packages/extension-base/src/services/request-service/handler/AuthRequestHandler.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,22 @@ export default class AuthRequestHandler {
9797
return addressList.reduce((addressList, v) => ({ ...addressList, [v]: value }), {});
9898
}
9999

100+
private getEcdsaAddressList (): Set<string> {
101+
const addressList = Object.keys(this.keyringService.context.pairs);
102+
const pairs = this.keyringService.context.pairs;
103+
const ecdsaAddressList = new Set<string>();
104+
105+
addressList.forEach((address) => {
106+
const pair = pairs[address];
107+
108+
if (pair && pair.json.meta.isSubstrateECDSA) {
109+
ecdsaAddressList.add(address);
110+
}
111+
});
112+
113+
return ecdsaAddressList;
114+
}
115+
100116
public get numAuthRequestsV2 (): number {
101117
return Object.keys(this.#authRequestsV2).length;
102118
}
@@ -220,11 +236,11 @@ export default class AuthRequestHandler {
220236
if (accountAuthTypes.length !== ALL_ACCOUNT_AUTH_TYPES.length) {
221237
const backupAllowed = (allowedAccounts || [])
222238
.filter((a) => {
223-
if (isEthereumAddress(a) && !accountAuthTypes.includes('evm')) {
239+
if (isEthereumAddress(a) && !accountAuthTypes.includes('evm') && !this.getEcdsaAddressList().has(a)) {
224240
return true;
225241
}
226242

227-
if (isSubstrateAddress(a) && !accountAuthTypes.includes('substrate')) {
243+
if ((isSubstrateAddress(a) || this.getEcdsaAddressList().has(a)) && !accountAuthTypes.includes('substrate')) {
228244
return true;
229245
}
230246

@@ -242,6 +258,8 @@ export default class AuthRequestHandler {
242258
backupAllowed.forEach((acc) => {
243259
isAllowedMap[acc] = true;
244260
});
261+
262+
console.log(backupAllowed, isAllowedMap, '123123', allowedAccounts);
245263
}
246264

247265
const defaultNetworkMap: Partial<Record<AccountAuthType, string>> = {};
@@ -388,9 +406,9 @@ export default class AuthRequestHandler {
388406

389407
allowedListByRequestType = accountAuthTypes.reduce<string[]>((list, accountAuthType) => {
390408
if (accountAuthType === 'evm') {
391-
list.push(...allowedListByRequestType.filter((a) => isEthereumAddress(a)));
409+
list.push(...allowedListByRequestType.filter((a) => isEthereumAddress(a) && !this.getEcdsaAddressList().has(a)));
392410
} else if (accountAuthType === 'substrate') {
393-
list.push(...allowedListByRequestType.filter((a) => isSubstrateAddress(a)));
411+
list.push(...allowedListByRequestType.filter((a) => isSubstrateAddress(a) || this.getEcdsaAddressList().has(a)));
394412
} else if (accountAuthType === 'ton') {
395413
list.push(...allowedListByRequestType.filter((a) => isTonAddress(a)));
396414
} else if (accountAuthType === 'cardano') {

packages/extension-base/src/utils/account/transform.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,11 @@ export const getAccountSignMode = (address: string, _meta?: KeyringPair$Meta): A
8888
if (meta.isExternal) {
8989
if (meta.isHardware) {
9090
if (meta.isGeneric) {
91+
if (meta.isSubstrateECDSA) {
92+
return AccountSignMode.ECDSA_SUBSTRATE_LEDGER;
93+
}
94+
9195
return AccountSignMode.GENERIC_LEDGER;
92-
} else if (meta.isSubstrateECDSA) {
93-
return AccountSignMode.ECDSA_SUBSTRATE_LEDGER;
9496
} else {
9597
return AccountSignMode.LEGACY_LEDGER;
9698
}

packages/extension-koni-ui/src/Popup/Account/RestoreJson/AccountRestoreJsonItem.tsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import { AccountChainType, AccountProxyExtra, AccountProxyType } from '@subwallet/extension-base/types';
4+
import { AccountProxyExtra, AccountProxyType } from '@subwallet/extension-base/types';
55
import { AccountChainTypeLogos, AccountProxyAvatar } from '@subwallet/extension-koni-ui/components';
66
import { useTranslation } from '@subwallet/extension-koni-ui/hooks';
77
import { Theme } from '@subwallet/extension-koni-ui/themes';
88
import { PhosphorIcon } from '@subwallet/extension-koni-ui/types';
9-
import { isSubstrateEcdsaAccountProxy } from '@subwallet/extension-koni-ui/utils';
109
import { Icon, Tooltip } from '@subwallet/react-ui';
1110
import CN from 'classnames';
1211
import { CheckCircle, Eye, GitCommit, Needle, QrCode, Question, Strategy, Swatches, Warning } from 'phosphor-react';
@@ -45,14 +44,7 @@ function Component (props: _AccountCardItem): React.ReactElement<_AccountCardIte
4544
onClick,
4645
showUnSelectedIcon } = props;
4746

48-
const { accountType, id: accountProxyId, name: accountName } = useMemo(() => accountProxy, [accountProxy]);
49-
const chainTypes = useMemo(() => {
50-
if (isSubstrateEcdsaAccountProxy(accountProxy)) {
51-
return [AccountChainType.SUBSTRATE];
52-
}
53-
54-
return accountProxy.chainTypes;
55-
}, [accountProxy]);
47+
const { accountType, chainTypes, id: accountProxyId, name: accountName } = useMemo(() => accountProxy, [accountProxy]);
5648
const { t } = useTranslation();
5749
const token = useContext<Theme>(ThemeContext as Context<Theme>).token;
5850
const disabledItem = useMemo(() => disabled || accountProxy.isExistAccount, [accountProxy.isExistAccount, disabled]);

packages/extension-koni-ui/src/Popup/Confirmations/index.tsx

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,25 +79,26 @@ const Component = function ({ className }: Props) {
7979
const address = request.request.payload.address;
8080

8181
account = findAccountByAddress(accounts, address) || undefined;
82-
const isEthereum = isEthereumAddress(address);
82+
const isEthereum = isEthereumAddress(address) && !account?.isSubstrateECDSA;
8383

8484
if (account?.isHardware) {
8585
if (account?.isGeneric) {
86-
canSign = !isEthereum;
86+
if (account.isSubstrateECDSA && !_isMessage) {
87+
const payload = request.request.payload as SignerPayloadJSON;
88+
const chainInfo = findChainInfoByGenesisHash(chainInfoMap, payload.genesisHash);
89+
90+
canSign = !!chainInfo && (_isChainEvmCompatible(chainInfo) && _isChainSubstrateCompatible(chainInfo));
91+
} else {
92+
canSign = !isEthereum;
93+
}
8794
} else {
8895
if (_isMessage) {
8996
canSign = true;
9097
} else {
9198
const payload = request.request.payload as SignerPayloadJSON;
9299

93-
if (account.isSubstrateECDSA) {
94-
const chainInfo = findChainInfoByGenesisHash(chainInfoMap, payload.genesisHash);
95-
96-
canSign = !!chainInfo && (_isChainEvmCompatible(chainInfo) && _isChainSubstrateCompatible(chainInfo));
97-
} else {
98-
// Valid even with evm ledger account (evm - availableGenesisHashes is empty)
99-
canSign = !!account?.availableGenesisHashes?.includes(payload.genesisHash) || _isRuntimeUpdated(payload?.signedExtensions);
100-
}
100+
// Valid even with evm ledger account (evm - availableGenesisHashes is empty)
101+
canSign = !!account?.availableGenesisHashes?.includes(payload.genesisHash) || _isRuntimeUpdated(payload?.signedExtensions);
101102
}
102103
}
103104
} else {

packages/extension-koni-ui/src/Popup/Confirmations/variants/AuthorizeConfirmation.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { useSetSelectedAccountTypes } from '@subwallet/extension-koni-ui/hooks';
1010
import { approveAuthRequestV2, cancelAuthRequestV2, rejectAuthRequestV2 } from '@subwallet/extension-koni-ui/messaging';
1111
import { RootState } from '@subwallet/extension-koni-ui/stores';
1212
import { ThemeProps } from '@subwallet/extension-koni-ui/types';
13-
import { convertAuthorizeTypeToChainTypes, filterAuthorizeAccountProxies, isAccountAll } from '@subwallet/extension-koni-ui/utils';
13+
import { convertAuthorizeTypeToChainTypes, filterAuthorizeAccountProxies, isAccountAll, isSubstrateEcdsaAccountProxy } from '@subwallet/extension-koni-ui/utils';
1414
import { KeypairType } from '@subwallet/keyring/types';
1515
import { Button, Icon } from '@subwallet/react-ui';
1616
import CN from 'classnames';
@@ -106,11 +106,11 @@ function Component ({ className, request }: Props) {
106106
const onConfirm = useCallback(() => {
107107
setLoading(true);
108108
const selectedAccountProxyIds = Object.keys(selectedMap).filter((key) => selectedMap[key]);
109-
const selectedAccounts = accounts.filter(({ chainType, proxyId }) => {
109+
const selectedAccounts = accounts.filter(({ chainType, isSubstrateECDSA, proxyId }) => {
110110
if (selectedAccountProxyIds.includes(proxyId || '')) {
111111
switch (chainType) {
112112
case AccountChainType.SUBSTRATE: return accountAuthTypes?.includes('substrate');
113-
case AccountChainType.ETHEREUM: return accountAuthTypes?.includes('evm');
113+
case AccountChainType.ETHEREUM: return isSubstrateECDSA ? accountAuthTypes?.includes('substrate') : accountAuthTypes?.includes('evm');
114114
case AccountChainType.TON: return accountAuthTypes?.includes('ton');
115115
case AccountChainType.CARDANO: return accountAuthTypes?.includes('cardano');
116116
}
@@ -241,7 +241,7 @@ function Component ({ className, request }: Props) {
241241
{visibleAccountProxies.map((item) => (
242242
<AccountProxyItem
243243
accountProxy={item}
244-
chainTypes={convertAuthorizeTypeToChainTypes(accountAuthTypes, item.chainTypes)}
244+
chainTypes={convertAuthorizeTypeToChainTypes(accountAuthTypes, item.chainTypes, isSubstrateEcdsaAccountProxy(item))}
245245
className={'__account-proxy-item'}
246246
isSelected={selectedMap[item.id]}
247247
key={item.id}

packages/extension-koni-ui/src/Popup/Settings/Security/ManageWebsiteAccess/Detail.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ function Component ({ accountAuthTypes, authInfo, className = '', goBack, origin
184184
return (
185185
<AccountProxyItem
186186
accountProxy={item}
187-
chainTypes={convertAuthorizeTypeToChainTypes(authInfo.accountAuthTypes, item.chainTypes)}
187+
chainTypes={convertAuthorizeTypeToChainTypes(authInfo.accountAuthTypes, item.chainTypes, isSubstrateEcdsaAccountProxy(item))}
188188
className={'__account-proxy-connect-item'}
189189
key={item.id}
190190
rightPartNode={(

packages/extension-koni-ui/src/components/AccountProxy/AccountProxyItem.tsx

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44
import { AccountChainType, AccountProxy } from '@subwallet/extension-base/types';
55
import { Theme } from '@subwallet/extension-koni-ui/themes';
66
import { ThemeProps } from '@subwallet/extension-koni-ui/types';
7-
import { isSubstrateEcdsaAccountProxy } from '@subwallet/extension-koni-ui/utils';
87
import { Icon } from '@subwallet/react-ui';
98
import CN from 'classnames';
109
import { CheckCircle } from 'phosphor-react';
11-
import React, { Context, useContext, useMemo } from 'react';
10+
import React, { Context, useContext } from 'react';
1211
import styled, { ThemeContext } from 'styled-components';
1312

1413
import AccountChainTypeLogos from './AccountChainTypeLogos';
@@ -30,13 +29,6 @@ type Props = ThemeProps & {
3029
function Component (props: Props): React.ReactElement<Props> {
3130
const { accountProxy, accountProxyName, chainTypes, className, isSelected, leftPartNode, onClick, renderRightPart, rightPartNode, showUnselectIcon } = props;
3231
const token = useContext<Theme>(ThemeContext as Context<Theme>).token;
33-
const accountChainTypes = useMemo(() => {
34-
if (isSubstrateEcdsaAccountProxy(accountProxy)) {
35-
return [AccountChainType.SUBSTRATE];
36-
}
37-
38-
return chainTypes;
39-
}, [accountProxy, chainTypes]);
4032
const checkedIconNode = ((showUnselectIcon || isSelected) && (
4133
<div className='__checked-icon-wrapper'>
4234
<Icon
@@ -51,7 +43,7 @@ function Component (props: Props): React.ReactElement<Props> {
5143
return (
5244
<div
5345
className={CN(className, {
54-
'-show-chain-type': !!accountChainTypes?.length
46+
'-show-chain-type': !!chainTypes?.length
5547
})}
5648
onClick={onClick}
5749
>
@@ -69,8 +61,8 @@ function Component (props: Props): React.ReactElement<Props> {
6961
<div className={'__account-name'}>
7062
{accountProxyName || accountProxy.name}
7163
</div>
72-
{!!accountChainTypes?.length && <AccountChainTypeLogos
73-
chainTypes={accountChainTypes}
64+
{!!chainTypes?.length && <AccountChainTypeLogos
65+
chainTypes={chainTypes}
7466
className={'__item-chain-type-logos'}
7567
/>}
7668
</div>

packages/extension-koni-ui/src/components/AccountProxy/AccountProxySelectorItem.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
// Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import { AccountChainType, AccountProxy, AccountProxyType } from '@subwallet/extension-base/types';
4+
import { AccountProxy, AccountProxyType } from '@subwallet/extension-base/types';
55
import { useTranslation } from '@subwallet/extension-koni-ui/hooks';
66
import { Theme } from '@subwallet/extension-koni-ui/themes';
77
import { PhosphorIcon, ThemeProps } from '@subwallet/extension-koni-ui/types';
8-
import { isSubstrateEcdsaAccountProxy } from '@subwallet/extension-koni-ui/utils';
98
import { Button, Icon } from '@subwallet/react-ui';
109
import CN from 'classnames';
1110
import { CheckCircle, Copy, Eye, GitCommit, GitMerge, Needle, PencilSimpleLine, QrCode, Question, Strategy, Swatches } from 'phosphor-react';
1211
import { IconWeight } from 'phosphor-react/src/lib';
13-
import React, { Context, useContext, useMemo } from 'react';
12+
import React, { Context, useContext } from 'react';
1413
import styled, { ThemeContext } from 'styled-components';
1514

1615
import AccountChainTypeLogos from './AccountChainTypeLogos';
@@ -43,13 +42,6 @@ function Component (props: Props): React.ReactElement<Props> {
4342
showDerivedPath } = props;
4443

4544
const token = useContext<Theme>(ThemeContext as Context<Theme>).token;
46-
const chainTypes = useMemo(() => {
47-
if (isSubstrateEcdsaAccountProxy(accountProxy)) {
48-
return [AccountChainType.SUBSTRATE];
49-
}
50-
51-
return accountProxy.chainTypes;
52-
}, [accountProxy]);
5345

5446
const { t } = useTranslation();
5547

@@ -173,7 +165,7 @@ function Component (props: Props): React.ReactElement<Props> {
173165
)
174166
: (
175167
<AccountChainTypeLogos
176-
chainTypes={chainTypes}
168+
chainTypes={accountProxy.chainTypes}
177169
className={'__item-chain-type-logos'}
178170
/>
179171
)

packages/extension-koni-ui/src/components/Layout/parts/ConnectWebsiteModal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { changeAuthorizationBlock, changeAuthorizationPerSite } from '@subwallet
1111
import { RootState } from '@subwallet/extension-koni-ui/stores';
1212
import { updateAuthUrls } from '@subwallet/extension-koni-ui/stores/utils';
1313
import { Theme, ThemeProps } from '@subwallet/extension-koni-ui/types';
14-
import { convertAuthorizeTypeToChainTypes, filterAuthorizeAccountProxies, isAddressAllowedWithAuthType } from '@subwallet/extension-koni-ui/utils';
14+
import { convertAuthorizeTypeToChainTypes, filterAuthorizeAccountProxies, isAddressAllowedWithAuthType, isSubstrateEcdsaAccountProxy } from '@subwallet/extension-koni-ui/utils';
1515
import { Button, Icon, NetworkItem, SwModal } from '@subwallet/react-ui';
1616
import CN from 'classnames';
1717
import { CaretRight, CheckCircle, GlobeHemisphereWest, ShieldCheck, ShieldSlash, XCircle } from 'phosphor-react';
@@ -304,7 +304,7 @@ function Component ({ authInfo, className = '', id, isBlocked = true, isNotConne
304304
return (
305305
<AccountProxyItem
306306
accountProxy={ap}
307-
chainTypes={convertAuthorizeTypeToChainTypes(authInfo?.accountAuthTypes, ap.chainTypes)}
307+
chainTypes={convertAuthorizeTypeToChainTypes(authInfo?.accountAuthTypes, ap.chainTypes, isSubstrateEcdsaAccountProxy(ap))}
308308
className={CN({
309309
'-is-current': isCurrent
310310
}, '__account-proxy-connect-item')}

0 commit comments

Comments
 (0)