Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Adding WalletConnect data to peer list and slices #1985

Open
wants to merge 1 commit into
base: add-wc-connect
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions apps/desktop/src/Router.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/* istanbul ignore file */
import { DynamicModalContext, useDynamicModal } from "@umami/components";
import { useDataPolling } from "@umami/data-polling";
import { WalletClient, useImplicitAccounts, useResetConnections } from "@umami/state";
import {
WalletClient,
useImplicitAccounts,
useResetBeaconConnections,
useResetWcConnections,
} from "@umami/state";
import { noop } from "lodash";
import { useEffect } from "react";
import { HashRouter, Navigate, Route, Routes } from "react-router-dom";
Expand Down Expand Up @@ -59,11 +64,13 @@ const LoggedInRouterWithPolling = () => {
};

const LoggedOutRouter = () => {
const resetBeaconConnections = useResetConnections();
const resetBeaconConnections = useResetBeaconConnections();
const resetWcConnections = useResetWcConnections();

useEffect(() => {
WalletClient.destroy().then(resetBeaconConnections).catch(noop);
}, [resetBeaconConnections]);
resetWcConnections();
}, [resetBeaconConnections, resetWcConnections]);

return (
<HashRouter>
Expand Down
12 changes: 6 additions & 6 deletions apps/desktop/src/utils/beacon/BeaconPeers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
Image,
Text,
} from "@chakra-ui/react";
import { useGetConnectionInfo, usePeers, useRemovePeer } from "@umami/state";
import { useBeaconPeers, useGetBeaconConnectionInfo, useRemoveBeaconPeer } from "@umami/state";
import { parsePkh } from "@umami/tezos";
import capitalize from "lodash/capitalize";
import { Fragment } from "react";
Expand All @@ -22,10 +22,10 @@ import colors from "../../style/colors";
/**
* Component displaying a list of connected dApps.
*
* Loads dApps data from {@link usePeers} hook & zips it with generated dAppIds.
* Loads dApps data from {@link useBeaconPeers} hook & zips it with generated dAppIds.
*/
export const BeaconPeers = () => {
const { peers } = usePeers();
const { peers } = useBeaconPeers();

if (peers.length === 0) {
return (
Expand Down Expand Up @@ -57,7 +57,7 @@ export const BeaconPeers = () => {
* @param onRemove - action for deleting dApp connection.
*/
const PeerRow = ({ peerInfo }: { peerInfo: ExtendedPeerInfo }) => {
const removePeer = useRemovePeer();
const removeBeaconPeer = useRemoveBeaconPeer();

return (
<Flex justifyContent="space-between" height="106px" data-testid="peer-row" paddingY="30px">
Expand All @@ -76,7 +76,7 @@ const PeerRow = ({ peerInfo }: { peerInfo: ExtendedPeerInfo }) => {
<IconButton
aria-label="Remove Peer"
icon={<TrashIcon />}
onClick={() => removePeer(peerInfo)}
onClick={() => removeBeaconPeer(peerInfo)}
size="xs"
variant="circle"
/>
Expand All @@ -94,7 +94,7 @@ const PeerRow = ({ peerInfo }: { peerInfo: ExtendedPeerInfo }) => {
* @param peerInfo - peerInfo provided by beacon Api + computed dAppId.
*/
const StoredPeerInfo = ({ peerInfo }: { peerInfo: ExtendedPeerInfo }) => {
const connectionInfo = useGetConnectionInfo(peerInfo.senderId);
const connectionInfo = useGetBeaconConnectionInfo(peerInfo.senderId);

if (!connectionInfo) {
return null;
Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/src/utils/beacon/PermissionRequestModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
import { useDynamicModalContext } from "@umami/components";
import {
WalletClient,
useAddConnection,
useAddBeaconConnection,
useAsyncActionHandler,
useGetImplicitAccount,
} from "@umami/state";
Expand All @@ -38,7 +38,7 @@ import { OwnedImplicitAccountsAutocomplete } from "../../components/AddressAutoc
import colors from "../../style/colors";

export const PermissionRequestModal = ({ request }: { request: PermissionRequestOutput }) => {
const addConnectionToBeaconSlice = useAddConnection();
const addConnectionToBeaconSlice = useAddBeaconConnection();
const getAccount = useGetImplicitAccount();
const { onClose } = useDynamicModalContext();
const { handleAsyncAction } = useAsyncActionHandler();
Expand Down
6 changes: 3 additions & 3 deletions apps/desktop/src/utils/beacon/useHandleBeaconMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
useAsyncActionHandler,
useFindNetwork,
useGetOwnedAccountSafe,
useRemovePeerBySenderId,
useRemoveBeaconPeerBySenderId,
} from "@umami/state";
import { type Network } from "@umami/tezos";

Expand All @@ -23,15 +23,15 @@ import { BeaconSignPage } from "../../components/SendFlow/Beacon/BeaconSignPage"
/**
* @returns a function that handles a beacon message and opens a modal with the appropriate content
*
* For operation requests it will also try to convert the operation(s) to our {@link Operation} format,
* For operation requests it will also try to convert the operation(s)n to our {@link Operation} format,
* estimate the fee and open the BeaconSignPage only if it succeeds
*/
export const useHandleBeaconMessage = () => {
const { openWith } = useDynamicModalContext();
const { handleAsyncAction } = useAsyncActionHandler();
const getAccount = useGetOwnedAccountSafe();
const findNetwork = useFindNetwork();
const removePeer = useRemovePeerBySenderId();
const removePeer = useRemoveBeaconPeerBySenderId();

// we should confirm that we support the network that the beacon request is coming from
const checkNetwork = ({
Expand Down
3 changes: 2 additions & 1 deletion apps/web/src/components/Menu/AppsMenu/AppsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Button, Divider, Text } from "@chakra-ui/react";
import { useAddPeer } from "@umami/state";

import { BeaconPeers } from "../../beacon";
import { useOnWalletConnect } from "../../WalletConnect";
import { WcPeers, useOnWalletConnect } from "../../WalletConnect";
import { DrawerContentWrapper } from "../DrawerContentWrapper";

export const AppsMenu = () => {
Expand Down Expand Up @@ -31,6 +31,7 @@ export const AppsMenu = () => {
</Button>
<Divider marginTop={{ base: "36px", md: "40px" }} />
<BeaconPeers />
<WcPeers />
</DrawerContentWrapper>
);
};
13 changes: 11 additions & 2 deletions apps/web/src/components/WalletConnect/SessionProposalModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@ import {
} from "@chakra-ui/react";
import { type WalletKitTypes } from "@reown/walletkit";
import { useDynamicModalContext } from "@umami/components";
import { useAsyncActionHandler, useGetImplicitAccount, walletKit } from "@umami/state";
import {
useAddWcConnection,
useAsyncActionHandler,
useGetImplicitAccount,
walletKit,
} from "@umami/state";
import { type NetworkName } from "@umami/tezos";
import { type SessionTypes } from "@walletconnect/types";
import { buildApprovedNamespaces, getSdkError } from "@walletconnect/utils";
import { FormProvider, useForm } from "react-hook-form";

Expand All @@ -32,6 +39,7 @@ export const SessionProposalModal = ({
proposal: WalletKitTypes.SessionProposal;
network: NetworkType;
}) => {
const addConnectionToWcSlice = useAddWcConnection();
const getAccount = useGetImplicitAccount();

const { onClose } = useDynamicModalContext();
Expand Down Expand Up @@ -62,11 +70,12 @@ export const SessionProposalModal = ({
},
});

await walletKit.approveSession({
const session: SessionTypes.Struct = await walletKit.approveSession({
id: proposal.id,
namespaces,
sessionProperties: {},
});
addConnectionToWcSlice(session, account.address.pkh, network.split(":")[1] as NetworkName);
onClose();
});

Expand Down
128 changes: 128 additions & 0 deletions apps/web/src/components/WalletConnect/WalletConnectPeers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { Center, Divider, Flex, Heading, IconButton, Image, Text, VStack } from "@chakra-ui/react";
import { useGetWcConnectionInfo, useRemoveWcPeer, useWcPeers } from "@umami/state";
import { parsePkh } from "@umami/tezos";
import { type SessionTypes } from "@walletconnect/types";
import { getSdkError } from "@walletconnect/utils";
import capitalize from "lodash/capitalize";

import { CodeSandboxIcon, StubIcon as TrashIcon } from "../../assets/icons";
import { useColor } from "../../styles/useColor";
import { AddressPill } from "../AddressPill/AddressPill";
import { EmptyMessage } from "../EmptyMessage";

/**
* Component displaying a list of connected dApps.
*
* Loads dApps data from {@link useWcPeers} hook & zips it with generated dAppIds.
*/
export const WcPeers = () => {
// const wcPeers: Record<string, SessionTypes.Struct> = walletKit.getActiveSessions();
const { peers: wcPeers } = useWcPeers();

console.log("wcPeers", wcPeers);

if (Object.keys(wcPeers).length === 0) {
return (
<EmptyMessage
alignItems="flex-start"
marginTop="40px"
data-testid="wc-peers-empty"
subtitle="No WalltConnect Apps to show"
title="Your WalletConnect Apps will appear here..."
/>
);
}

return (
<VStack
alignItems="flex-start"
gap="24px"
marginTop="24px"
data-testid="wc-peers"
divider={<Divider />}
spacing="0"
>
{
// loop peers and print PeerRow
Object.entries(wcPeers).map(([topic, peerInfo]) => (
<PeerRow key={topic} peerInfo={peerInfo} />
))
}
</VStack>
);
};

/**
* Component for displaying info about single connected dApp.
*
* @param peerInfo - peerInfo provided by wc Api + computed dAppId.
* @param onRemove - action for deleting dApp connection.
*/
const PeerRow = ({ peerInfo }: { peerInfo: SessionTypes.Struct }) => {
const color = useColor();
const removeWcPeer = useRemoveWcPeer();

return (
<Center
alignItems="center"
justifyContent="space-between"
width="full"
height="60px"
data-testid="peer-row"
>
<Flex height="100%">
<Center width="60px" marginRight="12px">
<Image
objectFit="cover"
fallback={<CodeSandboxIcon width="36px" height="36px" />}
src={peerInfo.peer.metadata.icons[0]}
/>
</Center>
<Center alignItems="flex-start" flexDirection="column" gap="6px">
<Heading color={color("900")} size="lg">
{peerInfo.peer.metadata.name}
</Heading>
<StoredPeerInfo peerInfo={peerInfo} />
</Center>
</Flex>
<IconButton
color={color("500")}
aria-label="Remove Peer"
icon={<TrashIcon />}
onClick={() =>
removeWcPeer({ topic: peerInfo.topic, reason: getSdkError("USER_DISCONNECTED") })
}
variant="iconButtonSolid"
/>
</Center>
);
};

/**
* Component for displaying additional info about connection with a dApp.
*
* Displays {@link AddressPill} with a connected account and network type,
* if information about the connection is stored in {@link wcSlice}.
*
* @param peerInfo - peerInfo provided by wc Api + computed dAppId.
*/
const StoredPeerInfo = ({ peerInfo }: { peerInfo: SessionTypes.Struct }) => {
const connectionInfo = useGetWcConnectionInfo(peerInfo.topic);

if (!connectionInfo) {
return null;
}

return (
<Flex>
<AddressPill marginRight="10px" address={parsePkh(connectionInfo.accountPkh)} />
<Divider marginRight="10px" orientation="vertical" />
<Text marginTop="2px" marginRight="4px" fontWeight={600} size="sm">
Network:
</Text>
<Text marginTop="2px" data-testid="dapp-connection-network" size="sm">
{capitalize(connectionInfo.networkName)}
</Text>
</Flex>
);
};
16 changes: 13 additions & 3 deletions apps/web/src/components/WalletConnect/WalletConnectProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
createWalletKit,
useAsyncActionHandler,
useAvailableNetworks,
useRemoveWcConnection,
useWcPeers,
walletKit,
} from "@umami/state";
import { type Network } from "@umami/tezos";
Expand Down Expand Up @@ -89,12 +91,20 @@ const useOnSessionRequest = () => {

// dApp can release WalletConnect session at any time and then the Wallet is notified by the WalletConnect server.
const useOnSessionDelete = () => {
const { handleAsyncAction } = useAsyncActionHandler();
const { peers, refresh } = useWcPeers();
const removeWcPeer = useRemoveWcConnection();
const toast = useToast();

return (event: WalletKitTypes.SessionDelete) =>
toast({
description: `dApp ${event.topic} released the connection.`,
status: "info",
handleAsyncAction(async () => {
const { topic } = event;
toast({
description: `Session deleted by dApp ${peers[topic].peer.metadata.name}`,
status: "info",
});
removeWcPeer(topic);
await refresh();
});
};

Expand Down
1 change: 1 addition & 0 deletions apps/web/src/components/WalletConnect/index.tsx
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./WalletConnectProvider";
export * from "./WalletConnectPeers";
10 changes: 5 additions & 5 deletions apps/web/src/components/beacon/BeaconPeers.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type ExtendedPeerInfo } from "@airgap/beacon-wallet";
import { Center, Divider, Flex, Heading, IconButton, Image, Text, VStack } from "@chakra-ui/react";
import { useGetConnectionInfo, usePeers, useRemovePeer } from "@umami/state";
import { useBeaconPeers, useGetBeaconConnectionInfo, useRemoveBeaconPeer } from "@umami/state";
import { parsePkh } from "@umami/tezos";
import capitalize from "lodash/capitalize";

Expand All @@ -12,10 +12,10 @@ import { EmptyMessage } from "../EmptyMessage";
/**
* Component displaying a list of connected dApps.
*
* Loads dApps data from {@link usePeers} hook & zips it with generated dAppIds.
* Loads dApps data from {@link useBeaconPeers} hook & zips it with generated dAppIds.
*/
export const BeaconPeers = () => {
const { peers } = usePeers();
const { peers } = useBeaconPeers();

if (peers.length === 0) {
return (
Expand Down Expand Up @@ -53,7 +53,7 @@ export const BeaconPeers = () => {
*/
const PeerRow = ({ peerInfo }: { peerInfo: ExtendedPeerInfo }) => {
const color = useColor();
const removePeer = useRemovePeer();
const removePeer = useRemoveBeaconPeer();

return (
<Center
Expand Down Expand Up @@ -98,7 +98,7 @@ const PeerRow = ({ peerInfo }: { peerInfo: ExtendedPeerInfo }) => {
* @param peerInfo - peerInfo provided by beacon Api + computed dAppId.
*/
const StoredPeerInfo = ({ peerInfo }: { peerInfo: ExtendedPeerInfo }) => {
const connectionInfo = useGetConnectionInfo(peerInfo.senderId);
const connectionInfo = useGetBeaconConnectionInfo(peerInfo.senderId);

if (!connectionInfo) {
return null;
Expand Down
Loading
Loading