Display active sessions on walletconnect page (#50)

* Replace QR icon with WC logo

* Change screen title

* Display active sessions

* Change title

* Display sessions on WalletConnect page

* Display session topic in list item

* Fix types

* Add line

* Change message

* Move useEffect to WalletConnectContext

* Disconnect sessions on resetting wallet

* Review changes

---------

Co-authored-by: Adw8 <adwait@deepstacksoft.com>
This commit is contained in:
Adwait Gharpure 2024-03-12 18:23:16 +05:30 committed by GitHub
parent 7219162185
commit cf197f386f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 179 additions and 80 deletions

35
App.tsx
View File

@ -1,8 +1,9 @@
import React, { useCallback, useEffect, useState } from 'react';
import { Button, Snackbar } from 'react-native-paper';
import { Button, Snackbar, Text } from 'react-native-paper';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { SignClientTypes } from '@walletconnect/types';
import { getSdkError } from '@walletconnect/utils';
import { useNavigation } from '@react-navigation/native';
import {
NativeStackNavigationProp,
@ -17,22 +18,19 @@ import PairingModal from './components/PairingModal';
import AddSession from './components/AddSession';
import WalletConnect from './components/WalletConnect';
import { StackParamsList } from './types';
import useInitialization, {
web3wallet,
} from './utils/wallet-connect/WalletConnectUtils';
import { web3wallet } from './utils/wallet-connect/WalletConnectUtils';
import { EIP155_SIGNING_METHODS } from './utils/wallet-connect/EIP155Lib';
import { getSignParamsMessage } from './utils/wallet-connect/Helpers';
import { useRequests } from './context/RequestContext';
import { useWalletConnect } from './context/WalletConnectContext';
const Stack = createNativeStackNavigator<StackParamsList>();
const App = (): React.JSX.Element => {
useInitialization();
const navigation =
useNavigation<NativeStackNavigationProp<StackParamsList>>();
const { requestSession, setRequestSession } = useRequests();
const { requestSession, setRequestSession, setActiveSessions } =
useWalletConnect();
const [modalVisible, setModalVisible] = useState(false);
const [toastVisible, setToastVisible] = useState(false);
@ -95,13 +93,20 @@ const App = (): React.JSX.Element => {
},
[requestSession, setRequestSession, navigation],
);
const onSessionDelete = useCallback(() => {
let sessions = web3wallet?.getActiveSessions();
setActiveSessions(sessions);
}, []);
useEffect(() => {
web3wallet?.on('session_proposal', onSessionProposal);
web3wallet?.on('session_request', onSessionRequest);
web3wallet?.on('session_delete', onSessionDelete);
return () => {
web3wallet?.off('session_proposal', onSessionProposal);
web3wallet?.off('session_request', onSessionRequest);
web3wallet?.off('session_delete', onSessionDelete);
};
//TODO: Investigate dependencies
});
@ -113,7 +118,7 @@ const App = (): React.JSX.Element => {
name="Laconic"
component={HomeScreen}
options={{
title: 'Laconic Wallet',
headerTitle: () => <Text variant="titleLarge">Laconic Wallet</Text>,
headerBackVisible: false,
}}
/>
@ -121,7 +126,7 @@ const App = (): React.JSX.Element => {
name="SignMessage"
component={SignMessage}
options={{
title: 'Sign Message',
headerTitle: () => <Text variant="titleLarge">Sign Message</Text>,
}}
initialParams={{ selectedNetwork: 'Ethereum' }}
/>
@ -129,14 +134,16 @@ const App = (): React.JSX.Element => {
name="SignRequest"
component={SignRequest}
options={{
title: 'Sign this message?',
headerTitle: () => (
<Text variant="titleLarge">Sign this message?</Text>
),
}}
/>
<Stack.Screen
name="InvalidPath"
component={InvalidPath}
options={{
title: 'Bad Request',
headerTitle: () => <Text variant="titleLarge">Bad Request</Text>,
headerBackVisible: false,
}}
/>
@ -144,7 +151,7 @@ const App = (): React.JSX.Element => {
name="WalletConnect"
component={WalletConnect}
options={{
title: 'WalletConnect Sessions',
headerTitle: () => <Text variant="titleLarge">WalletConnect</Text>,
headerRight: () => (
<Button
onPress={() => {

View File

@ -45,18 +45,7 @@ const AddSession = () => {
navigation.navigate('WalletConnect');
return pairing;
};
// const disconnect = async () => {
// const activeSessions = await web3wallet.getActiveSessions();
// const topic = Object.values(activeSessions)[0].topic;
// if (activeSessions) {
// await web3wallet.disconnectSession({
// topic,
// reason: getSdkError('USER_DISCONNECTED'),
// });
// navigation.navigate('Laconic');
// return;
// }
// };
useEffect(() => {
const handleAppStateChange = (newState: string) => {
setIsActive(newState === 'active');

View File

@ -1,14 +1,10 @@
import React, { useEffect, useState } from 'react';
import {
View,
ActivityIndicator,
TouchableHighlight,
Image,
} from 'react-native';
import { View, ActivityIndicator, Image } from 'react-native';
import { Button, Text } from 'react-native-paper';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { useNavigation } from '@react-navigation/native';
import { getSdkError } from '@walletconnect/utils';
import { createWallet, resetWallet, retrieveAccounts } from '../utils/accounts';
import { DialogComponent } from './Dialog';
@ -18,12 +14,14 @@ import CreateWallet from './CreateWallet';
import ResetWalletDialog from './ResetWalletDialog';
import styles from '../styles/stylesheet';
import { useAccounts } from '../context/AccountsContext';
import { useWalletConnect } from '../context/WalletConnectContext';
import { StackParamsList } from '../types';
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
const WCLogo = () => {
return (
<Image
style={{ width: 32, height: 20, margin: 0 }}
style={{ width: 24, height: 15, margin: 0 }}
source={require('../assets/WalletConnect-Icon-Blueberry.png')}
/>
);
@ -31,6 +29,7 @@ const WCLogo = () => {
const HomeScreen = () => {
const { accounts, setAccounts } = useAccounts();
const { setActiveSessions } = useWalletConnect();
const navigation =
useNavigation<NativeStackNavigationProp<StackParamsList>>();
@ -38,10 +37,9 @@ const HomeScreen = () => {
if (accounts.ethAccounts.length > 0) {
navigation.setOptions({
headerRight: () => (
<TouchableHighlight
onPress={() => navigation.navigate('WalletConnect')}>
<Button onPress={() => navigation.navigate('WalletConnect')}>
{<WCLogo />}
</TouchableHighlight>
</Button>
),
});
} else {
@ -86,6 +84,16 @@ const HomeScreen = () => {
cosmosAccounts: [],
});
setCurrentIndex(0);
const sessions = await web3wallet.getActiveSessions();
Object.keys(sessions).forEach(async sessionId => {
await web3wallet.disconnectSession({
topic: sessionId,
reason: getSdkError('USER_DISCONNECTED'),
});
});
setActiveSessions({});
hideResetDialog();
setNetwork('eth');
};

View File

@ -9,6 +9,7 @@ import { PairingModalProps } from '../types';
import styles from '../styles/stylesheet';
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
import { useAccounts } from '../context/AccountsContext';
import { useWalletConnect } from '../context/WalletConnectContext';
const PairingModal = ({
visible,
@ -92,6 +93,8 @@ const PairingModal = ({
});
}, [currentProposal]);
const { setActiveSessions } = useWalletConnect();
const handleAccept = async () => {
if (currentProposal) {
const { id, params } = currentProposal;
@ -140,6 +143,8 @@ const PairingModal = ({
namespaces,
});
const sessions = web3wallet.getActiveSessions();
setActiveSessions(sessions);
setModalVisible(false);
setToastVisible(true);
setCurrentProposal(undefined);

View File

@ -35,7 +35,7 @@ const SignMessage = ({ route }: SignProps) => {
<ScrollView style={styles.signPage}>
<View style={styles.accountInfo}>
<View>
<Text variant="headlineSmall">
<Text variant="titleMedium">
{account && `Account ${account.counterId + 1}`}
</Text>
</View>

View File

@ -18,12 +18,12 @@ import {
rejectEIP155Request,
} from '../utils/wallet-connect/WalletConnectRequests';
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
import { useRequests } from '../context/RequestContext';
import { useWalletConnect } from '../context/WalletConnectContext';
type SignRequestProps = NativeStackScreenProps<StackParamsList, 'SignRequest'>;
const SignRequest = ({ route }: SignRequestProps) => {
const { requestSession } = useRequests();
const { requestSession } = useWalletConnect();
const requestName = requestSession?.peer?.metadata?.name;
const requestIcon = requestSession?.peer?.metadata?.icons[0];

View File

@ -1,6 +1,71 @@
import React from 'react';
import { View, Text } from 'react-native';
import React, { useEffect } from 'react';
import { Image, TouchableOpacity, View } from 'react-native';
import { List, Text } from 'react-native-paper';
import { getSdkError } from '@walletconnect/utils';
import { useWalletConnect } from '../context/WalletConnectContext';
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
import styles from '../styles/stylesheet';
export default function WalletConnect() {
return <View />;
const { activeSessions, setActiveSessions } = useWalletConnect();
const disconnect = async (sessionId: string) => {
await web3wallet.disconnectSession({
topic: sessionId,
reason: getSdkError('USER_DISCONNECTED'),
});
const sessions = await web3wallet?.getActiveSessions();
setActiveSessions(sessions);
return;
};
useEffect(() => {
const sessions = web3wallet.getActiveSessions();
setActiveSessions(sessions);
}, []);
return (
<View>
{Object.keys(activeSessions).length > 0 ? (
<>
<View style={{ marginLeft: 12, marginTop: 12 }}>
<Text variant="titleMedium">Active Sessions</Text>
</View>
<List.Section>
{Object.entries(activeSessions).map(
([sessionId, session], index) => (
<List.Item
style={{ paddingLeft: 12, borderBottomWidth: 0.5 }}
key={sessionId}
title={`${session.peer.metadata.name}`}
descriptionNumberOfLines={7}
//TODO: Refactor
description={`${sessionId} \n\n${session.peer.metadata.url}\n\n${session.peer.metadata.description}`}
left={() => (
<Image
style={styles.dappLogo}
source={{ uri: session.peer.metadata.icons[0] }}
/>
)}
right={() => (
<TouchableOpacity
onPress={() => disconnect(sessionId)}
style={{ display: 'flex', justifyContent: 'center' }}>
<List.Icon icon="close" />
</TouchableOpacity>
)}
/>
),
)}
</List.Section>
</>
) : (
<View style={{ display: 'flex', alignItems: 'center', marginTop: 12 }}>
<Text>You have no active sessions</Text>
</View>
)}
</View>
);
}

View File

@ -1,31 +0,0 @@
import React, { createContext, useContext, useState } from 'react';
interface RequestContextProps {
requestSession: any;
setRequestSession: (requestSession: any) => void;
}
const RequestContext = createContext<RequestContextProps>({
requestSession: {},
setRequestSession: () => {},
});
const useRequests = () => {
const requestContext = useContext(RequestContext);
return requestContext;
};
const RequestProvider = ({ children }: { children: React.ReactNode }) => {
const [requestSession, setRequestSession] = useState<any>({});
return (
<RequestContext.Provider
value={{
requestSession,
setRequestSession,
}}>
{children}
</RequestContext.Provider>
);
};
export { useRequests, RequestProvider };

View File

@ -0,0 +1,48 @@
import React, { createContext, useContext, useEffect, useState } from 'react';
import { SessionTypes } from '@walletconnect/types';
import { WalletConnectContextProps } from '../types';
import useInitialization, {
web3wallet,
} from '../utils/wallet-connect/WalletConnectUtils';
const WalletConnectContext = createContext<WalletConnectContextProps>({
requestSession: {},
setRequestSession: () => {},
activeSessions: {},
setActiveSessions: () => {},
});
const useWalletConnect = () => {
const walletConnectContext = useContext(WalletConnectContext);
return walletConnectContext;
};
const WalletConnectProvider = ({ children }: { children: React.ReactNode }) => {
useInitialization();
useEffect(() => {
const sessions = web3wallet?.getActiveSessions() ?? {};
setActiveSessions(sessions);
}, []);
const [requestSession, setRequestSession] = useState<any>({});
const [activeSessions, setActiveSessions] = useState<
Record<string, SessionTypes.Struct>
>({});
return (
<WalletConnectContext.Provider
value={{
requestSession,
setRequestSession,
activeSessions,
setActiveSessions,
}}>
{children}
</WalletConnectContext.Provider>
);
};
export { useWalletConnect, WalletConnectProvider };

View File

@ -7,7 +7,7 @@ import { NavigationContainer } from '@react-navigation/native';
import App from './App';
import { AccountsProvider } from './context/AccountsContext';
import { RequestProvider } from './context/RequestContext';
import { WalletConnectProvider } from './context/WalletConnectContext';
import { name as appName } from './app.json';
export default function Main() {
@ -24,11 +24,11 @@ export default function Main() {
return (
<PaperProvider>
<AccountsProvider>
<RequestProvider>
<WalletConnectProvider>
<NavigationContainer linking={linking}>
<App />
</NavigationContainer>
</RequestProvider>
</WalletConnectProvider>
</AccountsProvider>
</PaperProvider>
);

View File

@ -18,7 +18,7 @@ const styles = StyleSheet.create({
fontWeight: '700',
},
accountContainer: {
marginTop: 24,
marginTop: 12,
},
addAccountButton: {
marginTop: 24,
@ -48,7 +48,7 @@ const styles = StyleSheet.create({
paddingHorizontal: 24,
},
accountInfo: {
marginTop: 24,
marginTop: 12,
marginBottom: 30,
},
networkDropdown: {

View File

@ -1,5 +1,4 @@
import { StdSignDoc } from '@cosmjs/amino';
import { SignClientTypes } from '@walletconnect/types';
import { SignClientTypes, SessionTypes } from '@walletconnect/types';
export type StackParamsList = {
Laconic: undefined;
@ -109,3 +108,12 @@ export interface SignModalProps {
requestEvent: SignClientTypes.EventArguments['session_request'] | undefined;
currentEthAddresses: string[];
}
export interface WalletConnectContextProps {
requestSession: any;
setRequestSession: (requestSession: any) => void;
activeSessions: Record<string, SessionTypes.Struct>;
setActiveSessions: (
activeSessions: Record<string, SessionTypes.Struct>,
) => void;
}