* Rebase ui branch * Fix scrollview (#69) * Add loading prop to button * Change function reference * Remove fragment --------- Co-authored-by: Adw8 <adwait@deepstacksoft.com> Co-authored-by: IshaVenikar <145848618+IshaVenikar@users.noreply.github.com>
270 lines
8.3 KiB
TypeScript
270 lines
8.3 KiB
TypeScript
import React, { useEffect, useMemo, useState } from 'react';
|
|
import { Image, View, Modal, ScrollView } from 'react-native';
|
|
import { Button, Text } from 'react-native-paper';
|
|
import mergeWith from 'lodash/mergeWith';
|
|
|
|
import { buildApprovedNamespaces, getSdkError } from '@walletconnect/utils';
|
|
|
|
import { AccountsState, 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';
|
|
import { EIP155_CHAINS } from '../utils/wallet-connect/EIP155Data';
|
|
import { COSMOS_CHAINS } from '../utils/wallet-connect/COSMOSData';
|
|
|
|
const PairingModal = ({
|
|
visible,
|
|
currentProposal,
|
|
setCurrentProposal,
|
|
setModalVisible,
|
|
setToastVisible,
|
|
}: PairingModalProps) => {
|
|
const { accounts, currentIndex } = useAccounts();
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
const dappName = currentProposal?.params?.proposer?.metadata.name;
|
|
const url = currentProposal?.params?.proposer?.metadata.url;
|
|
const icon = currentProposal?.params.proposer?.metadata.icons[0];
|
|
|
|
const [walletConnectData, setWalletConnectData] = useState<{
|
|
walletConnectMethods: string[];
|
|
walletConnectEvents: string[];
|
|
walletConnectChains: string[];
|
|
}>({
|
|
walletConnectMethods: [],
|
|
walletConnectEvents: [],
|
|
walletConnectChains: [],
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (!currentProposal) {
|
|
return;
|
|
}
|
|
const { params } = currentProposal;
|
|
const { requiredNamespaces, optionalNamespaces } = params;
|
|
|
|
setWalletConnectData({
|
|
walletConnectMethods: [],
|
|
walletConnectEvents: [],
|
|
walletConnectChains: [],
|
|
});
|
|
|
|
const combinedNamespaces = mergeWith(
|
|
requiredNamespaces,
|
|
optionalNamespaces,
|
|
(obj, src) =>
|
|
Array.isArray(obj) && Array.isArray(src) ? [...src, ...obj] : undefined,
|
|
);
|
|
Object.keys(combinedNamespaces).forEach(key => {
|
|
const { methods, events, chains } = combinedNamespaces[key];
|
|
|
|
setWalletConnectData(prevData => {
|
|
return {
|
|
walletConnectMethods: [...prevData.walletConnectMethods, ...methods],
|
|
walletConnectEvents: [...prevData.walletConnectEvents, ...events],
|
|
walletConnectChains: chains
|
|
? [...prevData.walletConnectChains, ...chains]
|
|
: [...prevData.walletConnectChains],
|
|
};
|
|
});
|
|
});
|
|
}, [currentProposal]);
|
|
|
|
const { setActiveSessions } = useWalletConnect();
|
|
|
|
const supportedNamespaces = useMemo(() => {
|
|
if (!currentProposal) {
|
|
return;
|
|
}
|
|
|
|
// eip155
|
|
const eip155Chains = Object.keys(EIP155_CHAINS);
|
|
|
|
// cosmos
|
|
const cosmosChains = Object.keys(COSMOS_CHAINS);
|
|
|
|
// Set selected account as the first account in supported namespaces
|
|
const sortedAccounts = Object.entries(accounts).reduce(
|
|
(acc: AccountsState, [key, value]) => {
|
|
let newValue = [...value];
|
|
|
|
// TODO: Implement selectedAccount instead of currentIndex in AccountsContext
|
|
if (value.length > currentIndex) {
|
|
const currentAccount = newValue[currentIndex];
|
|
const remainingAccounts = newValue.filter(
|
|
(_, index) => index !== currentIndex,
|
|
);
|
|
newValue = [currentAccount, ...remainingAccounts];
|
|
}
|
|
|
|
acc[key as 'ethAccounts' | 'cosmosAccounts'] = newValue;
|
|
return acc;
|
|
},
|
|
{ ethAccounts: [], cosmosAccounts: [] },
|
|
);
|
|
|
|
const { optionalNamespaces, requiredNamespaces } = currentProposal.params;
|
|
|
|
return {
|
|
eip155: {
|
|
chains: eip155Chains,
|
|
// TODO: Debug optional namespace methods and events being required for approval
|
|
methods: [
|
|
...(optionalNamespaces.eip155?.methods ?? []),
|
|
...(requiredNamespaces.eip155?.methods ?? []),
|
|
],
|
|
events: [
|
|
...(optionalNamespaces.eip155?.events ?? []),
|
|
...(requiredNamespaces.eip155?.events ?? []),
|
|
],
|
|
|
|
accounts: eip155Chains
|
|
.map(chain =>
|
|
sortedAccounts.ethAccounts.map(
|
|
account => `${chain}:${account.address}`,
|
|
),
|
|
)
|
|
.flat(),
|
|
},
|
|
cosmos: {
|
|
chains: cosmosChains,
|
|
methods: [
|
|
...(optionalNamespaces.cosmos?.methods ?? []),
|
|
...(requiredNamespaces.cosmos?.methods ?? []),
|
|
],
|
|
events: [
|
|
...(optionalNamespaces.cosmos?.events ?? []),
|
|
...(requiredNamespaces.cosmos?.events ?? []),
|
|
],
|
|
accounts: cosmosChains
|
|
.map(chain =>
|
|
sortedAccounts.cosmosAccounts.map(
|
|
account => `${chain}:${account.address}`,
|
|
),
|
|
)
|
|
.flat(),
|
|
},
|
|
};
|
|
}, [currentIndex, accounts, currentProposal]);
|
|
|
|
const namespaces = useMemo(() => {
|
|
return (
|
|
currentProposal &&
|
|
supportedNamespaces &&
|
|
buildApprovedNamespaces({
|
|
proposal: currentProposal.params,
|
|
supportedNamespaces,
|
|
})
|
|
);
|
|
}, [currentProposal, supportedNamespaces]);
|
|
|
|
const handleAccept = async () => {
|
|
try {
|
|
if (currentProposal && namespaces) {
|
|
setIsLoading(true);
|
|
const { id } = currentProposal;
|
|
|
|
await web3wallet!.approveSession({
|
|
id,
|
|
namespaces,
|
|
});
|
|
|
|
const sessions = web3wallet!.getActiveSessions();
|
|
setIsLoading(false);
|
|
setActiveSessions(sessions);
|
|
setModalVisible(false);
|
|
setToastVisible(true);
|
|
setCurrentProposal(undefined);
|
|
setWalletConnectData({
|
|
walletConnectMethods: [],
|
|
walletConnectEvents: [],
|
|
walletConnectChains: [],
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('Error in approve session:', error);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
const handleReject = async () => {
|
|
if (currentProposal) {
|
|
setIsLoading(true);
|
|
const { id } = currentProposal;
|
|
await web3wallet!.rejectSession({
|
|
id,
|
|
reason: getSdkError('USER_REJECTED_METHODS'),
|
|
});
|
|
|
|
setIsLoading(false);
|
|
setModalVisible(false);
|
|
setCurrentProposal(undefined);
|
|
setWalletConnectData({
|
|
walletConnectMethods: [],
|
|
walletConnectEvents: [],
|
|
walletConnectChains: [],
|
|
});
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Modal visible={visible} animationType="slide" transparent>
|
|
<View style={{ flex: 1 }}>
|
|
<View style={styles.modalContentContainer}>
|
|
<ScrollView showsVerticalScrollIndicator={true}>
|
|
<View style={styles.container}>
|
|
{icon && (
|
|
<Image
|
|
style={styles.dappLogo}
|
|
source={icon ? { uri: icon } : undefined}
|
|
/>
|
|
)}
|
|
|
|
<Text variant="titleMedium">{dappName}</Text>
|
|
<Text variant="bodyMedium">{url}</Text>
|
|
<View style={styles.marginVertical8} />
|
|
<Text variant="titleMedium">Connect to this site?</Text>
|
|
<Text variant="titleMedium">Chains:</Text>
|
|
{walletConnectData.walletConnectChains.map(chain => (
|
|
<Text style={styles.centerText} key={chain}>
|
|
{chain}
|
|
</Text>
|
|
))}
|
|
<View style={styles.marginVertical8}>
|
|
<Text variant="titleMedium">Methods Requested:</Text>
|
|
{walletConnectData.walletConnectMethods.map(method => (
|
|
<Text style={styles.centerText} key={method}>
|
|
{method}
|
|
</Text>
|
|
))}
|
|
</View>
|
|
|
|
<View style={styles.marginVertical8}>
|
|
<Text variant="titleMedium">Events Requested:</Text>
|
|
{walletConnectData.walletConnectEvents.map(event => (
|
|
<Text style={styles.centerText} key={event}>
|
|
{event}
|
|
</Text>
|
|
))}
|
|
</View>
|
|
</View>
|
|
</ScrollView>
|
|
|
|
<View style={styles.flexRow}>
|
|
<Button mode="contained" onPress={handleAccept} loading={isLoading}>
|
|
{isLoading ? 'Connecting' : 'Yes'}
|
|
</Button>
|
|
<View style={styles.space} />
|
|
<Button mode="outlined" onPress={handleReject}>
|
|
No
|
|
</Button>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
</Modal>
|
|
);
|
|
};
|
|
|
|
export default PairingModal;
|