forked from cerc-io/laconic-wallet
Handle incorrect RPC URL error and reject request (#112)
* Fix gas limit type for evm chains * Handle incorrect rpc url error * Fix edit network form not working for evm chains
This commit is contained in:
parent
db0b21ddd1
commit
b05b5894b0
@ -1,4 +1,12 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
extends: '@react-native',
|
extends: '@react-native',
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-unused-vars': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
ignoreRestSiblings: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -13,7 +13,7 @@ const TxErrorDialog = ({
|
|||||||
return (
|
return (
|
||||||
<Portal>
|
<Portal>
|
||||||
<Dialog visible={visible} onDismiss={hideDialog}>
|
<Dialog visible={visible} onDismiss={hideDialog}>
|
||||||
<Dialog.Title>Error sending transaction</Dialog.Title>
|
<Dialog.Title>Transaction Error</Dialog.Title>
|
||||||
<Dialog.Content>
|
<Dialog.Content>
|
||||||
<Text variant="bodyMedium">{error}</Text>
|
<Text variant="bodyMedium">{error}</Text>
|
||||||
</Dialog.Content>
|
</Dialog.Content>
|
||||||
|
@ -133,12 +133,17 @@ const ApproveTransaction = ({ route }: SignRequestProps) => {
|
|||||||
requestedNetwork?.addressPrefix,
|
requestedNetwork?.addressPrefix,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
const client = await SigningStargateClient.connectWithSigner(
|
const client = await SigningStargateClient.connectWithSigner(
|
||||||
requestedNetwork?.rpcUrl!,
|
requestedNetwork?.rpcUrl!,
|
||||||
sender,
|
sender,
|
||||||
);
|
);
|
||||||
|
|
||||||
setCosmosStargateClient(client);
|
setCosmosStargateClient(client);
|
||||||
|
} catch (error: any) {
|
||||||
|
setTxError(error.message);
|
||||||
|
setIsTxErrorDialogOpen(true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
setClient();
|
setClient();
|
||||||
@ -149,8 +154,16 @@ const ApproveTransaction = ({ route }: SignRequestProps) => {
|
|||||||
if (!requestedNetwork) {
|
if (!requestedNetwork) {
|
||||||
throw new Error('Requested chain not supported');
|
throw new Error('Requested chain not supported');
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
const ethProvider = new providers.JsonRpcProvider(
|
||||||
|
requestedNetwork.rpcUrl,
|
||||||
|
);
|
||||||
|
|
||||||
return new providers.JsonRpcProvider(requestedNetwork.rpcUrl);
|
return ethProvider;
|
||||||
|
} catch (error: any) {
|
||||||
|
setTxError(error.message);
|
||||||
|
setIsTxErrorDialogOpen(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [requestedNetwork, namespace]);
|
}, [requestedNetwork, namespace]);
|
||||||
|
|
||||||
@ -202,7 +215,6 @@ const ApproveTransaction = ({ route }: SignRequestProps) => {
|
|||||||
cosmosGasLimit,
|
cosmosGasLimit,
|
||||||
requestedNetwork,
|
requestedNetwork,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
retrieveData(transaction.from!);
|
retrieveData(transaction.from!);
|
||||||
}, [retrieveData, transaction]);
|
}, [retrieveData, transaction]);
|
||||||
@ -231,9 +243,10 @@ const ApproveTransaction = ({ route }: SignRequestProps) => {
|
|||||||
],
|
],
|
||||||
gas: cosmosGasLimit!,
|
gas: cosmosGasLimit!,
|
||||||
},
|
},
|
||||||
ethGasLimit: transaction.gasLimit
|
ethGasLimit:
|
||||||
? String(transaction.gasLimit)
|
namespace === EIP155
|
||||||
: ethGasLimit,
|
? BigNumber.from(transaction.gasLimit ?? ethGasLimit)
|
||||||
|
: undefined,
|
||||||
ethGasPrice: transaction.gasPrice
|
ethGasPrice: transaction.gasPrice
|
||||||
? String(transaction.gasPrice)
|
? String(transaction.gasPrice)
|
||||||
: ethGasPrice,
|
: ethGasPrice,
|
||||||
@ -245,7 +258,7 @@ const ApproveTransaction = ({ route }: SignRequestProps) => {
|
|||||||
await web3wallet!.respondSessionRequest({ topic, response });
|
await web3wallet!.respondSessionRequest({ topic, response });
|
||||||
navigation.navigate('Laconic');
|
navigation.navigate('Laconic');
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
setTxError(String(error));
|
setTxError(error.message);
|
||||||
setIsTxErrorDialogOpen(true);
|
setIsTxErrorDialogOpen(true);
|
||||||
}
|
}
|
||||||
setIsTxLoading(false);
|
setIsTxLoading(false);
|
||||||
@ -264,13 +277,15 @@ const ApproveTransaction = ({ route }: SignRequestProps) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const getAccountBalance = async () => {
|
const getAccountBalance = async () => {
|
||||||
|
try {
|
||||||
if (!account) {
|
if (!account) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (namespace === EIP155) {
|
if (namespace === EIP155) {
|
||||||
const fetchedBalance =
|
if (!provider) {
|
||||||
provider && (await provider.getBalance(account.address));
|
return;
|
||||||
|
}
|
||||||
|
const fetchedBalance = await provider.getBalance(account.address);
|
||||||
setBalance(fetchedBalance ? fetchedBalance.toString() : '0');
|
setBalance(fetchedBalance ? fetchedBalance.toString() : '0');
|
||||||
} else {
|
} else {
|
||||||
const cosmosBalance = await cosmosStargateClient?.getBalance(
|
const cosmosBalance = await cosmosStargateClient?.getBalance(
|
||||||
@ -280,6 +295,10 @@ const ApproveTransaction = ({ route }: SignRequestProps) => {
|
|||||||
|
|
||||||
setBalance(cosmosBalance?.amount!);
|
setBalance(cosmosBalance?.amount!);
|
||||||
}
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
setTxError(error.message);
|
||||||
|
setIsTxErrorDialogOpen(true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
getAccountBalance();
|
getAccountBalance();
|
||||||
@ -311,6 +330,7 @@ const ApproveTransaction = ({ route }: SignRequestProps) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const getEthGas = async () => {
|
const getEthGas = async () => {
|
||||||
|
try {
|
||||||
if (transaction.gasLimit && transaction.gasPrice) {
|
if (transaction.gasLimit && transaction.gasPrice) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -339,13 +359,17 @@ const ApproveTransaction = ({ route }: SignRequestProps) => {
|
|||||||
const gasLimit = await provider.estimateGas(transactionObject);
|
const gasLimit = await provider.estimateGas(transactionObject);
|
||||||
|
|
||||||
setEthGasLimit(String(gasLimit));
|
setEthGasLimit(String(gasLimit));
|
||||||
|
} catch (error: any) {
|
||||||
|
setTxError(error.message);
|
||||||
|
setIsTxErrorDialogOpen(true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
getEthGas();
|
getEthGas();
|
||||||
}, [provider, transaction, isSufficientFunds]);
|
}, [provider, transaction, isSufficientFunds]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const getCosmosGas = async () => {
|
const getCosmosGas = async () => {
|
||||||
|
try {
|
||||||
if (!cosmosStargateClient) {
|
if (!cosmosStargateClient) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -364,8 +388,11 @@ const ApproveTransaction = ({ route }: SignRequestProps) => {
|
|||||||
Math.round(gasEstimation * Number(Config.DEFAULT_GAS_ADJUSTMENT)),
|
Math.round(gasEstimation * Number(Config.DEFAULT_GAS_ADJUSTMENT)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
} catch (error: any) {
|
||||||
|
setTxError(error.message);
|
||||||
|
setIsTxErrorDialogOpen(true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
getCosmosGas();
|
getCosmosGas();
|
||||||
}, [cosmosStargateClient, isSufficientFunds, sendMsg, transaction]);
|
}, [cosmosStargateClient, isSufficientFunds, sendMsg, transaction]);
|
||||||
|
|
||||||
@ -479,7 +506,7 @@ const ApproveTransaction = ({ route }: SignRequestProps) => {
|
|||||||
visible={isTxErrorDialogOpen}
|
visible={isTxErrorDialogOpen}
|
||||||
hideDialog={() => {
|
hideDialog={() => {
|
||||||
setIsTxErrorDialogOpen(false);
|
setIsTxErrorDialogOpen(false);
|
||||||
if (!isSufficientFunds) {
|
if (!isSufficientFunds || !balance || !fees) {
|
||||||
rejectRequestHandler();
|
rejectRequestHandler();
|
||||||
navigation.navigate('Laconic');
|
navigation.navigate('Laconic');
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { ScrollView, View } from 'react-native';
|
import { ScrollView, View } from 'react-native';
|
||||||
import { useForm, Controller } from 'react-hook-form';
|
import { useForm, Controller, FieldErrors } from 'react-hook-form';
|
||||||
import { TextInput, Button, HelperText, Text } from 'react-native-paper';
|
import { TextInput, Button, HelperText, Text } from 'react-native-paper';
|
||||||
import { setInternetCredentials } from 'react-native-keychain';
|
import { setInternetCredentials } from 'react-native-keychain';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
@ -17,12 +17,25 @@ import styles from '../styles/stylesheet';
|
|||||||
import { retrieveNetworksData } from '../utils/accounts';
|
import { retrieveNetworksData } from '../utils/accounts';
|
||||||
import { useNetworks } from '../context/NetworksContext';
|
import { useNetworks } from '../context/NetworksContext';
|
||||||
import {
|
import {
|
||||||
|
COSMOS,
|
||||||
EIP155,
|
EIP155,
|
||||||
EMPTY_FIELD_ERROR,
|
EMPTY_FIELD_ERROR,
|
||||||
INVALID_URL_ERROR,
|
INVALID_URL_ERROR,
|
||||||
} from '../utils/constants';
|
} from '../utils/constants';
|
||||||
|
|
||||||
const networksFormDataSchema = z.object({
|
const ethNetworksFormSchema = z.object({
|
||||||
|
// Adding type field for resolving typescript error
|
||||||
|
type: z.literal(EIP155).optional(),
|
||||||
|
networkName: z.string().nonempty({ message: EMPTY_FIELD_ERROR }),
|
||||||
|
rpcUrl: z.string().url({ message: INVALID_URL_ERROR }),
|
||||||
|
blockExplorerUrl: z
|
||||||
|
.string()
|
||||||
|
.url({ message: INVALID_URL_ERROR })
|
||||||
|
.or(z.literal('')),
|
||||||
|
});
|
||||||
|
|
||||||
|
const cosmosNetworksFormDataSchema = z.object({
|
||||||
|
type: z.literal(COSMOS).optional(),
|
||||||
networkName: z.string().nonempty({ message: EMPTY_FIELD_ERROR }),
|
networkName: z.string().nonempty({ message: EMPTY_FIELD_ERROR }),
|
||||||
rpcUrl: z.string().url({ message: INVALID_URL_ERROR }),
|
rpcUrl: z.string().url({ message: INVALID_URL_ERROR }),
|
||||||
blockExplorerUrl: z
|
blockExplorerUrl: z
|
||||||
@ -42,6 +55,13 @@ const EditNetwork = ({ route }: EditNetworkProps) => {
|
|||||||
const navigation =
|
const navigation =
|
||||||
useNavigation<NativeStackNavigationProp<StackParamsList>>();
|
useNavigation<NativeStackNavigationProp<StackParamsList>>();
|
||||||
|
|
||||||
|
const networkData = route.params.selectedNetwork;
|
||||||
|
|
||||||
|
const networksFormDataSchema =
|
||||||
|
networkData.namespace === COSMOS
|
||||||
|
? cosmosNetworksFormDataSchema
|
||||||
|
: ethNetworksFormSchema;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
formState: { errors, isSubmitting },
|
formState: { errors, isSubmitting },
|
||||||
@ -50,13 +70,12 @@ const EditNetwork = ({ route }: EditNetworkProps) => {
|
|||||||
mode: 'onChange',
|
mode: 'onChange',
|
||||||
resolver: zodResolver(networksFormDataSchema),
|
resolver: zodResolver(networksFormDataSchema),
|
||||||
});
|
});
|
||||||
const networkData = route.params.selectedNetwork;
|
|
||||||
|
|
||||||
const submit = useCallback(
|
const submit = useCallback(
|
||||||
async (data: z.infer<typeof networksFormDataSchema>) => {
|
async (data: z.infer<typeof networksFormDataSchema>) => {
|
||||||
const retrievedNetworksData = await retrieveNetworksData();
|
const retrievedNetworksData = await retrieveNetworksData();
|
||||||
|
const { type, ...dataWithoutType } = data;
|
||||||
const newNetworkData = { ...networkData, ...data };
|
const newNetworkData = { ...networkData, ...dataWithoutType };
|
||||||
const index = retrievedNetworksData.findIndex(
|
const index = retrievedNetworksData.findIndex(
|
||||||
network => network.networkId === networkData.networkId,
|
network => network.networkId === networkData.networkId,
|
||||||
);
|
);
|
||||||
@ -137,7 +156,7 @@ const EditNetwork = ({ route }: EditNetworkProps) => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{networkData.namespace !== EIP155 ? (
|
{networkData.namespace === COSMOS && (
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="gasPrice"
|
name="gasPrice"
|
||||||
@ -151,11 +170,19 @@ const EditNetwork = ({ route }: EditNetworkProps) => {
|
|||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
onChangeText={onChange}
|
onChangeText={onChange}
|
||||||
/>
|
/>
|
||||||
<HelperText type="error">{errors.gasPrice?.message}</HelperText>
|
<HelperText type="error">
|
||||||
|
{
|
||||||
|
(
|
||||||
|
errors as FieldErrors<
|
||||||
|
z.infer<typeof cosmosNetworksFormDataSchema>
|
||||||
|
>
|
||||||
|
).gasPrice?.message
|
||||||
|
}
|
||||||
|
</HelperText>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
) : null}
|
)}
|
||||||
<Button
|
<Button
|
||||||
mode="contained"
|
mode="contained"
|
||||||
loading={isSubmitting}
|
loading={isSubmitting}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Taken from https://medium.com/walletconnect/how-to-build-a-wallet-in-react-native-with-the-web3wallet-sdk-b6f57bf02f9a
|
// Taken from https://medium.com/walletconnect/how-to-build-a-wallet-in-react-native-with-the-web3wallet-sdk-b6f57bf02f9a
|
||||||
import { Wallet, providers } from 'ethers';
|
import { BigNumber, Wallet, providers } from 'ethers';
|
||||||
|
|
||||||
import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils';
|
import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils';
|
||||||
import { SignClientTypes } from '@walletconnect/types';
|
import { SignClientTypes } from '@walletconnect/types';
|
||||||
@ -36,7 +36,7 @@ export async function approveWalletConnectRequest({
|
|||||||
message?: string;
|
message?: string;
|
||||||
provider?: providers.JsonRpcProvider | SigningStargateClient;
|
provider?: providers.JsonRpcProvider | SigningStargateClient;
|
||||||
cosmosFee?: StdFee;
|
cosmosFee?: StdFee;
|
||||||
ethGasLimit?: string;
|
ethGasLimit?: BigNumber;
|
||||||
ethGasPrice?: string;
|
ethGasPrice?: string;
|
||||||
sendMsg?: MsgSendEncodeObject;
|
sendMsg?: MsgSendEncodeObject;
|
||||||
memo?: string;
|
memo?: string;
|
||||||
|
Loading…
Reference in New Issue
Block a user