Skip to content

Commit

Permalink
[Issue-1874] Allow Polkadot namespace use EVM address via WalletConnect
Browse files Browse the repository at this point in the history
  • Loading branch information
Quangdm-cdm committed Jan 10, 2025
1 parent e0f577a commit 2217d16
Show file tree
Hide file tree
Showing 16 changed files with 157 additions and 107 deletions.
2 changes: 1 addition & 1 deletion html/DevModeWeb.bundle/site/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><title>SubWallet</title><script inline inline-asset="fallback.js$" inline-asset-delete></script><script inline inline-asset="web-runner.js$" inline-asset-delete></script><script defer="defer" src="fallback-0b81a7f9f3a8fbf3b257.js"></script><script defer="defer" src="web-runner-e3836fbe8eb063db5a88.js"></script></head><body><div id="root">SubWallet</div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"><title>SubWallet</title><script inline inline-asset="fallback.js$" inline-asset-delete></script><script inline inline-asset="web-runner.js$" inline-asset-delete></script><script defer="defer" src="fallback-0b81a7f9f3a8fbf3b257.js"></script><script defer="defer" src="web-runner-29461d321f6b930dc736.js"></script></head><body><div id="root">SubWallet</div></body></html>

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion html/Web.bundle/site/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><title>SubWallet</title><script inline inline-asset="fallback.js$" inline-asset-delete></script><script inline inline-asset="web-runner.js$" inline-asset-delete></script><script defer="defer" src="fallback-0b81a7f9f3a8fbf3b257.js"></script><script defer="defer" src="web-runner-7ef576356afe78e6d44f.js"></script></head><body><div id="root">SubWallet</div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"><title>SubWallet</title><script inline inline-asset="fallback.js$" inline-asset-delete></script><script inline inline-asset="web-runner.js$" inline-asset-delete></script><script defer="defer" src="fallback-0b81a7f9f3a8fbf3b257.js"></script><script defer="defer" src="web-runner-833394d31ed408db3bbe.js"></script></head><body><div id="root">SubWallet</div></body></html>

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions src/components/WalletConnect/Account/WCAccountSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,31 @@ import AccountItemWithName from 'components/common/Account/Item/AccountItemWithN
import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants';
import { CheckCircle } from 'phosphor-react-native';
import { ModalRef } from 'types/modalRef';
import { AccountJson } from '@subwallet/extension-base/types';
import { AccountChainType, AccountJson } from '@subwallet/extension-base/types';
import { isSameAddress } from '@subwallet/extension-base/utils';

interface Props {
selectedAccounts: string[];
appliedAccounts: string[];
availableAccounts: AccountJson[];
accountType: AccountChainType;
onSelectAccount: (account: string, applyImmediately?: boolean) => VoidFunction;
useModal: boolean;
onApply: () => void;
onCancel: () => void;
namespace: string;
}

const renderButtonIcon = (color: string) => <Icon phosphorIcon={CheckCircle} weight={'fill'} iconColor={color} />;

export const WCAccountSelect = ({
accountType,
appliedAccounts,
availableAccounts,
onApply,
onCancel,
onSelectAccount,
selectedAccounts,
useModal,
namespace,
}: Props) => {
const modalRef = useRef<ModalRef>();

Expand Down Expand Up @@ -72,26 +72,26 @@ export const WCAccountSelect = ({
);

const noAccountTitle = useMemo(() => {
switch (namespace) {
case 'polkadot':
switch (accountType) {
case AccountChainType.SUBSTRATE:
return i18n.formatString(i18n.common.noAvailableAccount, 'Substrate') as string;
case 'eip155':
case AccountChainType.ETHEREUM:
return i18n.formatString(i18n.common.noAvailableAccount, 'EVM') as string;
default:
return i18n.formatString(i18n.common.noAvailableAccount, '') as string;
}
}, [namespace]);
}, [accountType]);

const noAccountDescription = useMemo(() => {
switch (namespace) {
case 'polkadot':
switch (accountType) {
case AccountChainType.SUBSTRATE:
return i18n.formatString(i18n.common.youDonotHaveAnyAcc, 'Substrate') as string;
case 'eip155':
case AccountChainType.ETHEREUM:
return i18n.formatString(i18n.common.youDonotHaveAnyAcc, 'EVM') as string;
default:
return i18n.formatString(i18n.common.youDonotHaveAnyAcc, '') as string;
}
}, [namespace]);
}, [accountType]);

return (
<View style={{ width: '100%' }}>
Expand Down
3 changes: 2 additions & 1 deletion src/components/WalletConnect/Network/WCNetworkSelected.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ export const WCNetworkSelected = ({ networks }: Props) => {
name:
unSupportNetworks.length <= 1
? i18n.message.unknownNetwork
: i18n.formatString(i18n.message.unknownNetworks, unSupportNetworks.length),
: (i18n.formatString(i18n.message.unknownNetworks, unSupportNetworks.length) as string),
},
slug: '',
wcChain: '',
}
: null;

Expand Down
182 changes: 105 additions & 77 deletions src/hooks/wallet-connect/useSelectWalletConnectAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,64 +10,73 @@ import {
isSupportWalletConnectNamespace,
} from '@subwallet/extension-base/services/wallet-connect-service/helpers';
import { isSameAddress, reformatAddress, uniqueStringArray } from '@subwallet/extension-base/utils';
import {
WALLET_CONNECT_EIP155_NAMESPACE,
WALLET_CONNECT_POLKADOT_NAMESPACE,
WALLET_CONNECT_SUPPORT_NAMESPACES,
} from '@subwallet/extension-base/services/wallet-connect-service/constants';
import { WALLET_CONNECT_SUPPORT_NAMESPACES } from '@subwallet/extension-base/services/wallet-connect-service/constants';
import { ProposalTypes } from '@walletconnect/types';
import { chainsToWalletConnectChainInfos } from 'utils/walletConnect';
import { AccountJson } from '@subwallet/extension-base/types';
import { AccountChainType, AccountJson } from '@subwallet/extension-base/types';

interface SelectAccount {
availableAccounts: AccountJson[];
networks: WalletConnectChainInfo[];
accountType: AccountChainType;
selectedAccounts: string[];
appliedAccounts: string[];
}

const useSelectWalletConnectAccount = (params: ProposalTypes.Struct) => {
// Result by acc
const [result, setResult] = useState<Record<string, SelectAccount>>({});

const { accounts } = useSelector((state: RootState) => state.accountState);
const { chainInfoMap } = useSelector((state: RootState) => state.chainStore);

const noAllAccount = useMemo(() => accounts.filter(({ address }) => !isAccountAll(address)), [accounts]);

const namespaces: Record<string, WalletConnectChainInfo[]> = useMemo(() => {
const accountTypeMap = useMemo(() => {
const availableNamespaces: Record<string, string[]> = {};
const _result: Record<string, WalletConnectChainInfo[]> = {};

Object.entries(params.requiredNamespaces).forEach(([key, namespace]) => {
if (isSupportWalletConnectNamespace(key)) {
if (namespace.chains) {
availableNamespaces[key] = namespace.chains;
params.requiredNamespaces &&
Object.entries(params.requiredNamespaces).forEach(([key, namespace]) => {
if (isSupportWalletConnectNamespace(key)) {
if (namespace.chains) {
availableNamespaces[key] = namespace.chains;
}
}
}
});
});

Object.entries(params.optionalNamespaces).forEach(([key, namespace]) => {
if (isSupportWalletConnectNamespace(key)) {
if (namespace.chains) {
const requiredNameSpace = availableNamespaces[key];
const defaultChains: string[] = [];

if (requiredNameSpace) {
availableNamespaces[key] = [
...(requiredNameSpace || defaultChains),
...(namespace.chains || defaultChains),
];
} else {
if (namespace.chains.length) {
availableNamespaces[key] = namespace.chains;
params.optionalNamespaces &&
Object.entries(params.optionalNamespaces).forEach(([key, namespace]) => {
if (isSupportWalletConnectNamespace(key)) {
if (namespace.chains) {
const requiredNameSpace = availableNamespaces[key];
const defaultChains: string[] = [];

if (requiredNameSpace) {
availableNamespaces[key] = [
...(requiredNameSpace || defaultChains),
...(namespace.chains || defaultChains),
];
} else {
if (namespace.chains.length) {
availableNamespaces[key] = namespace.chains;
}
}
}
}
}
});
});
for (const chains of Object.values(availableNamespaces)) {
const wcChains = chainsToWalletConnectChainInfos(chainInfoMap, uniqueStringArray(chains));

for (const chain of wcChains) {
if (chain.accountType) {
if (!_result[chain.accountType]) {
_result[chain.accountType] = [];
}

for (const [namespace, chains] of Object.entries(availableNamespaces)) {
_result[namespace] = chainsToWalletConnectChainInfos(chainInfoMap, uniqueStringArray(chains));
_result[chain.accountType].push(chain);
}
}
}

return _result;
Expand All @@ -76,15 +85,19 @@ const useSelectWalletConnectAccount = (params: ProposalTypes.Struct) => {
const supportedChains = useMemo(() => {
const chains: string[] = [];

for (const [key, namespace] of Object.entries(params.requiredNamespaces)) {
if (isSupportWalletConnectNamespace(key)) {
chains.push(...(namespace.chains || []));
if (params.requiredNamespaces) {
for (const [key, namespace] of Object.entries(params.requiredNamespaces)) {
if (isSupportWalletConnectNamespace(key)) {
chains.push(...(namespace.chains || []));
}
}
}

for (const [key, namespace] of Object.entries(params.optionalNamespaces)) {
if (isSupportWalletConnectNamespace(key)) {
chains.push(...(namespace.chains || []));
if (params.optionalNamespaces) {
for (const [key, namespace] of Object.entries(params.optionalNamespaces)) {
if (isSupportWalletConnectNamespace(key)) {
chains.push(...(namespace.chains || []));
}
}
}

Expand All @@ -94,45 +107,59 @@ const useSelectWalletConnectAccount = (params: ProposalTypes.Struct) => {
}, [chainInfoMap, params.optionalNamespaces, params.requiredNamespaces]);

const missingType = useMemo((): AccountAuthType[] => {
const _result: AccountAuthType[] = [];

Object.keys(params.requiredNamespaces).forEach(namespace => {
const setAccountTypes = Object.entries(params.requiredNamespaces || {}).reduce((rs, [namespace, data]) => {
if (WALLET_CONNECT_SUPPORT_NAMESPACES.includes(namespace)) {
const available = noAllAccount.some(acc => {
if (namespace === WALLET_CONNECT_EIP155_NAMESPACE && acc.chainType === 'ethereum') {
return true;
} else if (namespace === WALLET_CONNECT_POLKADOT_NAMESPACE && acc.chainType === 'substrate') {
return true;
const chains = chainsToWalletConnectChainInfos(chainInfoMap, uniqueStringArray(data.chains || []));

for (const chain of chains) {
if (chain.chainInfo && chain.accountType) {
rs.add(chain.accountType);
}
}
}

return false;
});
return rs;
}, new Set<AccountChainType>());

if (!available) {
_result.push(WALLET_CONNECT_EIP155_NAMESPACE === namespace ? 'evm' : 'substrate');
}
const missingAccountTypes = Array.from(setAccountTypes);

for (const account of noAllAccount) {
if (missingAccountTypes.includes(account.chainType)) {
missingAccountTypes.splice(missingAccountTypes.indexOf(account.chainType), 1);
}
});
}

return _result;
}, [noAllAccount, params.requiredNamespaces]);
return missingAccountTypes.map((value): AccountAuthType => {
switch (value) {
case AccountChainType.ETHEREUM:
return 'evm';
case AccountChainType.SUBSTRATE:
return 'substrate';
case AccountChainType.TON:
return 'ton';
default:
throw new Error(`Unsupported account type: ${value}`);
}
});
}, [noAllAccount, params.requiredNamespaces, chainInfoMap]);

const isUnSupportCase = useMemo(
() =>
Object.values(params.requiredNamespaces)
Object.values(params.requiredNamespaces || {})
.map(namespace => namespace.chains || [])
.flat()
.some(chain => !isSupportWalletConnectChain(chain, chainInfoMap)),
[chainInfoMap, params.requiredNamespaces],
);

const isExitedAnotherUnsupportedNamespace = useMemo(
() =>
params.requiredNamespaces &&
Object.keys(params.requiredNamespaces).some(namespace => !isSupportWalletConnectNamespace(namespace)),
[params.requiredNamespaces],
);
const supportOneChain = useMemo(() => supportedChains.length === 1, [supportedChains]);
const supportOneNamespace = useMemo(() => Object.keys(namespaces).length === 1, [namespaces]);
const supportOneAccountType = useMemo(() => Object.keys(accountTypeMap).length === 1, [accountTypeMap]);
const noNetwork = useMemo((): boolean => {
return (
(!params.requiredNamespaces || !Object.keys(params.requiredNamespaces).length) &&
Expand Down Expand Up @@ -201,38 +228,39 @@ const useSelectWalletConnectAccount = (params: ProposalTypes.Struct) => {
});
}, []);

// const abiCoder = noAllAccount.filter(acc => {
// return acc.chainType === accountType;
// })

// console.log('abiCoder', abiCoder);

useEffect(() => {
setResult(oldState => {
const _result: Record<string, SelectAccount> = {};

const selectReplace = JSON.stringify(namespaces) !== JSON.stringify(namespaceRef.current);

for (const [namespace, networks] of Object.entries(namespaces)) {
if (WALLET_CONNECT_SUPPORT_NAMESPACES.includes(namespace)) {
_result[namespace] = {
networks,
selectedAccounts: selectReplace ? [] : oldState[namespace]?.selectedAccounts || [],
appliedAccounts: selectReplace ? [] : oldState[namespace]?.appliedAccounts || [],
availableAccounts: noAllAccount.filter(acc => {
if (namespace === WALLET_CONNECT_EIP155_NAMESPACE && acc.chainType === 'ethereum') {
return true;
} else if (namespace === WALLET_CONNECT_POLKADOT_NAMESPACE && acc.chainType === 'substrate') {
return true;
}
const selectReplace = JSON.stringify(accountTypeMap) !== JSON.stringify(namespaceRef.current);

return false;
}),
};
}
for (const [_accountType, networks] of Object.entries(accountTypeMap)) {
const accountType = _accountType as AccountChainType;

_result[accountType] = {
networks,
selectedAccounts: selectReplace ? [] : oldState[accountType]?.selectedAccounts || [],
appliedAccounts: selectReplace ? [] : oldState[accountType]?.appliedAccounts || [],
availableAccounts: noAllAccount.filter(acc => {
return acc.chainType === accountType;
}),
accountType,
};
}

return _result;
});

return () => {
namespaceRef.current = namespaces;
namespaceRef.current = accountTypeMap;
};
}, [noAllAccount, namespaces]);
}, [noAllAccount, accountTypeMap]);

useEffect(() => {
const callback = (): boolean => {
Expand Down Expand Up @@ -263,13 +291,13 @@ const useSelectWalletConnectAccount = (params: ProposalTypes.Struct) => {
isUnSupportCase,
missingType,
namespaceAccounts: result,
noNetwork,
onApplyAccounts,
onCancelSelectAccounts,
onSelectAccount,
isExitedAnotherUnsupportedNamespace,
supportOneChain,
noNetwork,
supportOneNamespace,
supportOneAccountType,
supportedChains,
};
};
Expand Down
1 change: 1 addition & 0 deletions src/screens/Confirmations/parts/Sign/Substrate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ export const SubstrateSignArea = (props: Props) => {
showQuoteExpired ||
loadingChain ||
hashLoading ||
loading ||
(isMessage ? !modeCanSignMessage.includes(signMode) : alertData?.type === 'error')
}
icon={getButtonIcon(approveIcon)}
Expand Down
Loading

0 comments on commit 2217d16

Please sign in to comment.