Part of [laconicd testnet validator enrollment](https://www.notion.so/laconicd-testnet-validator-enrollment-6fc1d3cafcc64fef8c5ed3affa27c675) - Remove path config used for deep links Co-authored-by: Shreerang Kale <shreerangkale@gmail.com> Reviewed-on: cerc-io/laconic-wallet-web#7
323 lines
9.1 KiB
TypeScript
323 lines
9.1 KiB
TypeScript
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
import { Image, ScrollView, View } from 'react-native';
|
|
import { ActivityIndicator, Button, Text, Appbar } from 'react-native-paper';
|
|
|
|
import { useNavigation } from '@react-navigation/native';
|
|
import {
|
|
NativeStackNavigationProp,
|
|
NativeStackScreenProps,
|
|
} from '@react-navigation/native-stack';
|
|
import { getHeaderTitle } from '@react-navigation/elements';
|
|
|
|
import { Account, StackParamsList } from '../types';
|
|
import AccountDetails from '../components/AccountDetails';
|
|
import styles from '../styles/stylesheet';
|
|
import { signMessage } from '../utils/sign-message';
|
|
import { retrieveSingleAccount } from '../utils/accounts';
|
|
import {
|
|
approveWalletConnectRequest,
|
|
rejectWalletConnectRequest,
|
|
WalletConnectRequests,
|
|
} from '../utils/wallet-connect/wallet-connect-requests';
|
|
import { useWalletConnect } from '../context/WalletConnectContext';
|
|
import { EIP155_SIGNING_METHODS } from '../utils/wallet-connect/EIP155Data';
|
|
import { useNetworks } from '../context/NetworksContext';
|
|
import { COSMOS_METHODS } from '../utils/wallet-connect/COSMOSData';
|
|
|
|
type SignRequestProps = NativeStackScreenProps<StackParamsList, 'SignRequest'>;
|
|
|
|
const SignRequest = ({ route }: SignRequestProps) => {
|
|
const { networksData } = useNetworks();
|
|
const {web3wallet} = useWalletConnect();
|
|
|
|
const requestSession = route.params.requestSessionData;
|
|
const requestName = requestSession?.peer?.metadata?.name;
|
|
const requestIcon = requestSession?.peer?.metadata?.icons[0];
|
|
const requestURL = requestSession?.peer?.metadata?.url;
|
|
|
|
const [account, setAccount] = useState<Account>();
|
|
const [message, setMessage] = useState<string>('');
|
|
const [namespace, setNamespace] = useState<string>('');
|
|
const [chainId, setChainId] = useState<string>('');
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const [isApproving, setIsApproving] = useState(false);
|
|
const [isRejecting, setIsRejecting] = useState(false);
|
|
|
|
const navigation =
|
|
useNavigation<NativeStackNavigationProp<StackParamsList>>();
|
|
|
|
const isCosmosSignDirect = useMemo(() => {
|
|
const requestParams = route.params.requestEvent;
|
|
|
|
if (!requestParams?.id) {
|
|
return false;
|
|
}
|
|
|
|
return requestParams.params.request.method === 'cosmos_signDirect';
|
|
}, [route.params]);
|
|
|
|
const isEthSendTransaction = useMemo(() => {
|
|
const requestParams = route.params.requestEvent;
|
|
|
|
if (!requestParams?.id) {
|
|
return false;
|
|
}
|
|
|
|
return (
|
|
requestParams.params.request.method ===
|
|
EIP155_SIGNING_METHODS.ETH_SEND_TRANSACTION
|
|
);
|
|
}, [route.params]);
|
|
|
|
const retrieveData = useCallback(
|
|
async (
|
|
requestNamespace: string,
|
|
requestChainId: string,
|
|
requestAddress: string,
|
|
requestMessage: string,
|
|
) => {
|
|
const requestAccount = await retrieveSingleAccount(
|
|
requestNamespace,
|
|
requestChainId,
|
|
requestAddress,
|
|
);
|
|
if (!requestAccount) {
|
|
navigation.navigate('InvalidPath');
|
|
return;
|
|
}
|
|
|
|
setAccount(requestAccount);
|
|
setMessage(decodeURIComponent(requestMessage));
|
|
setNamespace(requestNamespace);
|
|
setChainId(requestChainId);
|
|
setIsLoading(false);
|
|
},
|
|
[navigation],
|
|
);
|
|
|
|
const sanitizePath = useCallback(
|
|
(path: string) => {
|
|
const regex = /^\/sign\/(eip155|cosmos)\/(.+)\/(.+)\/(.+)$/;
|
|
const match = path.match(regex);
|
|
if (match) {
|
|
const [, pathNamespace, pathChainId, pathAddress, pathMessage] = match;
|
|
return {
|
|
namespace: pathNamespace,
|
|
chainId: pathChainId,
|
|
address: pathAddress,
|
|
message: pathMessage,
|
|
};
|
|
} else {
|
|
navigation.navigate('InvalidPath');
|
|
}
|
|
return null;
|
|
},
|
|
[navigation],
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (route.path) {
|
|
const sanitizedRoute = sanitizePath(route.path);
|
|
sanitizedRoute &&
|
|
retrieveData(
|
|
sanitizedRoute.namespace,
|
|
sanitizedRoute.chainId,
|
|
sanitizedRoute.address,
|
|
sanitizedRoute.message,
|
|
);
|
|
return;
|
|
}
|
|
const requestEvent = route.params.requestEvent;
|
|
const requestChainId = requestEvent?.params.chainId;
|
|
|
|
const requestedChain = networksData.find(
|
|
networkData => networkData.chainId === requestChainId?.split(':')[1],
|
|
);
|
|
|
|
retrieveData(
|
|
requestedChain!.namespace,
|
|
requestedChain!.chainId,
|
|
route.params.address,
|
|
route.params.message,
|
|
);
|
|
}, [retrieveData, sanitizePath, route, networksData]);
|
|
|
|
const handleWalletConnectRequest = async () => {
|
|
const { requestEvent } = route.params || {};
|
|
|
|
if (!account) {
|
|
throw new Error('account not found');
|
|
}
|
|
|
|
if (!requestEvent) {
|
|
throw new Error('Request event not found');
|
|
}
|
|
|
|
let options: WalletConnectRequests;
|
|
|
|
switch (requestEvent.params.request.method) {
|
|
case COSMOS_METHODS.COSMOS_SIGN_DIRECT:
|
|
options = {
|
|
type: 'cosmos_signDirect',
|
|
message,
|
|
};
|
|
break;
|
|
case COSMOS_METHODS.COSMOS_SIGN_AMINO:
|
|
options = {
|
|
type: 'cosmos_signAmino',
|
|
message,
|
|
};
|
|
break;
|
|
case EIP155_SIGNING_METHODS.PERSONAL_SIGN:
|
|
options = {
|
|
type: 'personal_sign',
|
|
message,
|
|
};
|
|
break;
|
|
|
|
default:
|
|
throw new Error('Invalid Method');
|
|
}
|
|
|
|
const response = await approveWalletConnectRequest(
|
|
requestEvent,
|
|
account,
|
|
namespace,
|
|
chainId,
|
|
options,
|
|
);
|
|
|
|
const { topic } = requestEvent;
|
|
await web3wallet!.respondSessionRequest({ topic, response });
|
|
};
|
|
|
|
const handleIntent = async () => {
|
|
if (!account) {
|
|
throw new Error('Account is not valid');
|
|
}
|
|
if (message) {
|
|
const signedMessage = await signMessage({
|
|
message,
|
|
namespace,
|
|
chainId,
|
|
accountId: account.index,
|
|
});
|
|
alert(`Signature ${signedMessage}`);
|
|
}
|
|
};
|
|
|
|
const signMessageHandler = async () => {
|
|
setIsApproving(true);
|
|
if (route.params.requestEvent) {
|
|
await handleWalletConnectRequest();
|
|
} else {
|
|
await handleIntent();
|
|
}
|
|
|
|
setIsApproving(false);
|
|
navigation.navigate('Home');
|
|
};
|
|
|
|
const rejectRequestHandler = async () => {
|
|
setIsRejecting(true);
|
|
if (route.params?.requestEvent) {
|
|
const response = rejectWalletConnectRequest(route.params?.requestEvent);
|
|
const { topic } = route.params?.requestEvent;
|
|
await web3wallet!.respondSessionRequest({
|
|
topic,
|
|
response,
|
|
});
|
|
}
|
|
|
|
setIsRejecting(false);
|
|
navigation.navigate('Home');
|
|
};
|
|
|
|
useEffect(() => {
|
|
navigation.setOptions({
|
|
// eslint-disable-next-line react/no-unstable-nested-components
|
|
header: ({ options, back }) => {
|
|
const title = getHeaderTitle(options, 'Sign Request');
|
|
|
|
return (
|
|
<Appbar.Header>
|
|
{back && (
|
|
<Appbar.BackAction
|
|
onPress={async () => {
|
|
await rejectRequestHandler();
|
|
navigation.navigate('Home');
|
|
}}
|
|
/>
|
|
)}
|
|
<Appbar.Content title={title} />
|
|
</Appbar.Header>
|
|
);
|
|
},
|
|
});
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [navigation, route.name]);
|
|
|
|
return (
|
|
<>
|
|
{isLoading ? (
|
|
<View style={styles.spinnerContainer}>
|
|
<ActivityIndicator size="large" color="#0000ff" />
|
|
</View>
|
|
) : (
|
|
<>
|
|
<ScrollView contentContainerStyle={styles.appContainer}>
|
|
<View style={styles.dappDetails}>
|
|
{requestIcon && (
|
|
<>
|
|
{requestIcon.endsWith('.svg') ? (
|
|
<View style={styles.dappLogo}>
|
|
<Text>SvgURI requstIcon</Text>
|
|
</View>
|
|
) : (
|
|
<Image
|
|
style={styles.dappLogo}
|
|
source={{ uri: requestIcon }}
|
|
/>
|
|
)}
|
|
</>
|
|
)}
|
|
<Text>{requestName}</Text>
|
|
<Text variant="bodyMedium">{requestURL}</Text>
|
|
</View>
|
|
<AccountDetails account={account} />
|
|
{isCosmosSignDirect || isEthSendTransaction ? (
|
|
<View style={styles.requestDirectMessage}>
|
|
<ScrollView nestedScrollEnabled>
|
|
<Text variant="bodyLarge">{message}</Text>
|
|
</ScrollView>
|
|
</View>
|
|
) : (
|
|
<View style={styles.requestMessage}>
|
|
<Text variant="bodyLarge">{message}</Text>
|
|
</View>
|
|
)}
|
|
</ScrollView>
|
|
<View style={styles.buttonContainer}>
|
|
<Button
|
|
mode="contained"
|
|
onPress={signMessageHandler}
|
|
loading={isApproving}
|
|
disabled={isApproving}>
|
|
Yes
|
|
</Button>
|
|
<Button
|
|
mode="contained"
|
|
onPress={rejectRequestHandler}
|
|
loading={isRejecting}
|
|
buttonColor="#B82B0D">
|
|
No
|
|
</Button>
|
|
</View>
|
|
</>
|
|
)}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default SignRequest;
|