Skip to content

Commit

Permalink
feat(suite): show network details in walletconnect proposal
Browse files Browse the repository at this point in the history
  • Loading branch information
martykan committed Feb 13, 2025
1 parent cafd764 commit 1c150ab
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import {
sessionProposalApproveThunk,
sessionProposalRejectThunk,
} from '@suite-common/walletconnect';
import { Banner, H2, NewModal, Note, Paragraph } from '@trezor/components';
import { Banner, Card, H2, NewModal, Note, Paragraph, Row, Text } from '@trezor/components';
import { BannerButton } from '@trezor/components/src/components/Banner/BannerButton';
import { CoinLogo } from '@trezor/product-components';
import { spacings } from '@trezor/theme';

import { onCancel } from 'src/actions/suite/modalActions';
import { goto } from 'src/actions/suite/routerActions';
import { Translation } from 'src/components/suite';
import { useDispatch, useSelector } from 'src/hooks/suite';

Expand Down Expand Up @@ -74,6 +77,66 @@ export const WalletConnectProposalModal = ({ eventId }: WalletConnectProposalMod
<Translation id="TR_WALLETCONNECT_REQUEST" />
</Paragraph>

<Card margin={{ top: spacings.xs }} paddingType="small">
{['active', 'inactive', 'unsupported'].map(status => {
const filteredNetworks = pendingProposal.networks.filter(
network => network.status == status,
);
if (!filteredNetworks?.length) return null;

return (
<>
<Text variant="tertiary">{`Requested networks - ${status}: `}</Text>
<Row
key={status}
rowGap={spacings.xs}
columnGap={spacings.sm}
flexWrap="wrap"
margin={{ bottom: spacings.sm }}
>
{filteredNetworks.map(network => (
<Row key={network.namespaceId} gap={spacings.xs}>
{network.symbol && (
<CoinLogo
type="network"
symbol={network.symbol as any}
size={24}
/>
)}
<Text>
{network.name}
{network.required && (
<Text variant="destructive">*</Text>
)}
</Text>
</Row>
))}
</Row>
</>
);
})}
</Card>
{pendingProposal.networks.some(
network => network.required && network.status !== 'active',
) && (
<Banner
variant="warning"
margin={{ top: spacings.xs }}
rightContent={
<BannerButton
onClick={() => dispatch(goto('settings-coins'))}
icon="arrowRight"
iconAlignment="right"
>
Coin settings
</BannerButton>
}
>
Some required networks are not activated. Please activate them to ensure proper
compatibility with the app.
</Banner>
)}

{pendingProposal.isScam && (
<Banner variant="destructive" margin={{ top: spacings.xs }}>
<Translation id="TR_WALLETCONNECT_IS_SCAM" />
Expand Down
86 changes: 75 additions & 11 deletions suite-common/walletconnect/src/walletConnectThunks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { WalletKit, WalletKitTypes } from '@reown/walletkit';
import { WalletKit as WalletKitClient } from '@reown/walletkit/dist/types/client';
import { Core } from '@walletconnect/core';
import type { ProposalTypes } from '@walletconnect/types';
import {
buildApprovedNamespaces,
buildAuthObject,
Expand All @@ -10,7 +11,7 @@ import {

import { createThunk } from '@suite-common/redux-utils';
import { notificationsActions } from '@suite-common/toast-notifications';
import { getNetwork } from '@suite-common/wallet-config';
import { getNetwork, networksCollection } from '@suite-common/wallet-config';
import { selectAccounts, selectSelectedDevice } from '@suite-common/wallet-core';
import { Account } from '@suite-common/wallet-types';
import TrezorConnect from '@trezor/connect';
Expand All @@ -19,6 +20,7 @@ import { getAdapterByMethod, getNamespaces } from './adapters';
import { walletConnectActions } from './walletConnectActions';
import { PROJECT_ID, WALLETCONNECT_METADATA, WALLETCONNECT_MODULE } from './walletConnectConstants';
import { selectPendingProposal } from './walletConnectReducer';
import { PendingConnectionProposalNetwork } from './walletConnectTypes';

let walletKit: WalletKitClient;

Expand Down Expand Up @@ -82,12 +84,64 @@ export const sessionAuthenticateThunk = createThunk<
}
});

export const sessionProposalThunk = createThunk<
void,
{
event: WalletKitTypes.SessionProposal;
}
>(`${WALLETCONNECT_MODULE}/sessionProposalThunk`, ({ event }, { dispatch, getState }) => {
// Check supported networks
const accounts = selectAccounts(getState());
const networks: PendingConnectionProposalNetwork[] = [];
const processNamespace =
(required: boolean) =>
([key, namespace]: [string, ProposalTypes.RequiredNamespace]) => {
if (key === 'eip155') {
namespace.chains?.forEach(chain => {
const alreadyAdded = networks.some(network => network.namespaceId === chain);
if (alreadyAdded) return;
const supported = networksCollection.find(
nc => chain === `eip155:${nc.chainId}`,
);
const getStatus = () => {
if (!supported) return 'unsupported';
const hasAccounts = accounts.some(
account => account.symbol === supported?.symbol,
);
if (hasAccounts) return 'active';

return 'inactive';
};
networks.push({
namespaceId: chain,
symbol: supported?.symbol,
name: supported?.name ?? `Unknown (${chain})`,
status: getStatus(),
required,
});
});
}
};
Object.entries(event.params.requiredNamespaces).forEach(processNamespace(true));
Object.entries(event.params.optionalNamespaces).forEach(processNamespace(false));

dispatch(
walletConnectActions.createSessionProposal({
eventId: event.id,
params: event.params,
expired: false,
networks,
...event.verifyContext.verified,
}),
);
});

export const sessionRequestThunk = createThunk<
void,
{
event: WalletKitTypes.SessionRequest;
}
>(`${WALLETCONNECT_MODULE}/sessionProposalThunk`, async ({ event }, { dispatch }) => {
>(`${WALLETCONNECT_MODULE}/sessionRequestThunk`, async ({ event }, { dispatch }) => {
try {
const adapter = getAdapterByMethod(event.params.request.method);
if (!adapter) {
Expand Down Expand Up @@ -132,7 +186,11 @@ export const sessionProposalApproveThunk = createThunk<
async ({ eventId }, { dispatch, getState }) => {
try {
const pendingProposal = selectPendingProposal(getState());
if (!pendingProposal || pendingProposal.eventId !== eventId) {
if (
!pendingProposal ||
pendingProposal.eventId !== eventId ||
pendingProposal.expired
) {
throw new Error('Proposal not found');
}

Expand All @@ -142,6 +200,18 @@ export const sessionProposalApproveThunk = createThunk<
proposal: pendingProposal.params,
supportedNamespaces,
});
// No supported accounts found
if (
!Object.values(approvedNamespaces).some(namespace => namespace.accounts.length > 0)
) {
await walletKit.rejectSession({
id: eventId,
reason: getSdkError('UNSUPPORTED_ACCOUNTS'),
});

return;
}

const session = await walletKit.approveSession({
id: eventId,
namespaces: approvedNamespaces,
Expand Down Expand Up @@ -180,6 +250,7 @@ export const switchSelectedAccountThunk = createThunk<void, { account: Account }
`${WALLETCONNECT_MODULE}/switchSelectedAccountThunk`,
async ({ account }) => {
const network = getNetwork(account.symbol);
if (!network || !network.chainId) return;
const sessions = await walletKit.getActiveSessions();
for (const topic in sessions) {
walletKit.emitSessionEvent({
Expand Down Expand Up @@ -242,14 +313,7 @@ export const walletConnectInitThunk = createThunk(
});

walletKit.on('session_proposal', event => {
dispatch(
walletConnectActions.createSessionProposal({
eventId: event.id,
params: event.params,
expired: false,
...event.verifyContext.verified,
}),
);
dispatch(sessionProposalThunk({ event }));
});

walletKit.on('proposal_expire', () => {
Expand Down
9 changes: 9 additions & 0 deletions suite-common/walletconnect/src/walletConnectTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ export interface WalletConnectSession {
};
}

export interface PendingConnectionProposalNetwork {
namespaceId: string;
symbol?: string;
name: string;
status: 'active' | 'inactive' | 'unsupported';
required: boolean;
}

export interface PendingConnectionProposal {
eventId: number;
params: ProposalTypes.Struct;
Expand All @@ -47,4 +55,5 @@ export interface PendingConnectionProposal {
verifyUrl: string;
isScam?: boolean;
expired: boolean;
networks: PendingConnectionProposalNetwork[];
}

0 comments on commit 1c150ab

Please sign in to comment.