forked from cerc-io/laconic-wallet
Add functionality to configure EVM networks (#74)
* Configure EVM networks * Display added EVM networks in network drop down * Add network for configured networks
This commit is contained in:
parent
0dea0082b4
commit
703ea72c1f
@ -31,6 +31,7 @@
|
|||||||
"patch-package": "^8.0.0",
|
"patch-package": "^8.0.0",
|
||||||
"postinstall-postinstall": "^2.1.0",
|
"postinstall-postinstall": "^2.1.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
"react-hook-form": "^7.51.2",
|
||||||
"react-native": "0.73.3",
|
"react-native": "0.73.3",
|
||||||
"react-native-config": "^1.5.1",
|
"react-native-config": "^1.5.1",
|
||||||
"react-native-get-random-values": "^1.10.0",
|
"react-native-get-random-values": "^1.10.0",
|
||||||
|
@ -26,6 +26,7 @@ import { web3wallet } from './utils/wallet-connect/WalletConnectUtils';
|
|||||||
import { EIP155_SIGNING_METHODS } from './utils/wallet-connect/EIP155Data';
|
import { EIP155_SIGNING_METHODS } from './utils/wallet-connect/EIP155Data';
|
||||||
import { getSignParamsMessage } from './utils/wallet-connect/Helpers';
|
import { getSignParamsMessage } from './utils/wallet-connect/Helpers';
|
||||||
import ApproveTransaction from './screens/ApproveTransaction';
|
import ApproveTransaction from './screens/ApproveTransaction';
|
||||||
|
import AddNetwork from './screens/AddNetwork';
|
||||||
|
|
||||||
const Stack = createNativeStackNavigator<StackParamsList>();
|
const Stack = createNativeStackNavigator<StackParamsList>();
|
||||||
|
|
||||||
@ -220,6 +221,13 @@ const App = (): React.JSX.Element => {
|
|||||||
title: 'Approve transaction',
|
title: 'Approve transaction',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="AddNetwork"
|
||||||
|
component={AddNetwork}
|
||||||
|
options={{
|
||||||
|
title: 'Add Network',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
<PairingModal
|
<PairingModal
|
||||||
visible={modalVisible}
|
visible={modalVisible}
|
||||||
|
@ -187,6 +187,19 @@ const Accounts = ({
|
|||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.signLink}>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => {
|
||||||
|
navigation.navigate('AddNetwork');
|
||||||
|
}}>
|
||||||
|
<Text
|
||||||
|
variant="titleSmall"
|
||||||
|
style={[styles.hyperlink, { color: theme.colors.primary }]}>
|
||||||
|
Add Network
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
|
@ -1,14 +1,34 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { View } from 'react-native';
|
import { View } from 'react-native';
|
||||||
import { List } from 'react-native-paper';
|
import { List } from 'react-native-paper';
|
||||||
|
|
||||||
import { NetworkDropdownProps } from '../types';
|
import { NetworkDropdownProps } from '../types';
|
||||||
import styles from '../styles/stylesheet';
|
import styles from '../styles/stylesheet';
|
||||||
|
import { useAccounts } from '../context/AccountsContext';
|
||||||
|
|
||||||
const NetworkDropdown = ({ updateNetwork }: NetworkDropdownProps) => {
|
const NetworkDropdown = ({ updateNetwork }: NetworkDropdownProps) => {
|
||||||
const [expanded, setExpanded] = useState<boolean>(false);
|
const [expanded, setExpanded] = useState<boolean>(false);
|
||||||
const [selectedNetwork, setSelectedNetwork] = useState<string>('Ethereum');
|
const [selectedNetwork, setSelectedNetwork] = useState<string>('Ethereum');
|
||||||
|
|
||||||
|
const { networksData } = useAccounts();
|
||||||
|
|
||||||
|
const networks = useMemo(() => {
|
||||||
|
const defaultNetworks = [
|
||||||
|
{ value: 'eth', chainId: 'eip155:1', displayName: 'Ethereum' },
|
||||||
|
{ value: 'cosmos', chainId: 'cosmos:cosmoshub-4', displayName: 'Cosmos' },
|
||||||
|
];
|
||||||
|
|
||||||
|
networksData.forEach(network => {
|
||||||
|
defaultNetworks.push({
|
||||||
|
value: network.networkType,
|
||||||
|
chainId: network.chainId,
|
||||||
|
displayName: network.networkName,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return defaultNetworks;
|
||||||
|
}, [networksData]);
|
||||||
|
|
||||||
const handleNetworkPress = (network: string, displayName: string) => {
|
const handleNetworkPress = (network: string, displayName: string) => {
|
||||||
updateNetwork(network);
|
updateNetwork(network);
|
||||||
setSelectedNetwork(displayName);
|
setSelectedNetwork(displayName);
|
||||||
@ -23,7 +43,7 @@ const NetworkDropdown = ({ updateNetwork }: NetworkDropdownProps) => {
|
|||||||
onPress={() => setExpanded(!expanded)}>
|
onPress={() => setExpanded(!expanded)}>
|
||||||
{networks.map(network => (
|
{networks.map(network => (
|
||||||
<List.Item
|
<List.Item
|
||||||
key={network.value}
|
key={network.chainId}
|
||||||
title={network.displayName}
|
title={network.displayName}
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
handleNetworkPress(network.value, network.displayName)
|
handleNetworkPress(network.value, network.displayName)
|
||||||
@ -35,9 +55,4 @@ const NetworkDropdown = ({ updateNetwork }: NetworkDropdownProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const networks = [
|
|
||||||
{ value: 'eth', displayName: 'Ethereum' },
|
|
||||||
{ value: 'cosmos', displayName: 'Cosmos' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export { NetworkDropdown };
|
export { NetworkDropdown };
|
||||||
|
@ -1,17 +1,25 @@
|
|||||||
import React, { createContext, useContext, useState } from 'react';
|
import React, { createContext, useContext, useState } from 'react';
|
||||||
|
|
||||||
import { AccountsState } from '../types';
|
import { AccountsState, NetworksDataState } from '../types';
|
||||||
|
|
||||||
const AccountsContext = createContext<{
|
const AccountsContext = createContext<{
|
||||||
accounts: AccountsState;
|
accounts: AccountsState;
|
||||||
setAccounts: (account: AccountsState) => void;
|
setAccounts: (account: AccountsState) => void;
|
||||||
currentIndex: number;
|
currentIndex: number;
|
||||||
setCurrentIndex: (index: number) => void;
|
setCurrentIndex: (index: number) => void;
|
||||||
|
networksData: NetworksDataState[];
|
||||||
|
setNetworksData: (networksDataArray: NetworksDataState[]) => void;
|
||||||
|
networkType: string;
|
||||||
|
setNetworkType: (networkType: string) => void;
|
||||||
}>({
|
}>({
|
||||||
accounts: { ethAccounts: [], cosmosAccounts: [] },
|
accounts: { ethAccounts: [], cosmosAccounts: [] },
|
||||||
setAccounts: () => {},
|
setAccounts: () => {},
|
||||||
currentIndex: 0,
|
currentIndex: 0,
|
||||||
setCurrentIndex: () => {},
|
setCurrentIndex: () => {},
|
||||||
|
networksData: [],
|
||||||
|
setNetworksData: () => {},
|
||||||
|
networkType: '',
|
||||||
|
setNetworkType: () => {},
|
||||||
});
|
});
|
||||||
|
|
||||||
const useAccounts = () => {
|
const useAccounts = () => {
|
||||||
@ -24,10 +32,21 @@ const AccountsProvider = ({ children }: { children: any }) => {
|
|||||||
ethAccounts: [],
|
ethAccounts: [],
|
||||||
cosmosAccounts: [],
|
cosmosAccounts: [],
|
||||||
});
|
});
|
||||||
|
const [networksData, setNetworksData] = useState<NetworksDataState[]>([]);
|
||||||
const [currentIndex, setCurrentIndex] = useState<number>(0);
|
const [currentIndex, setCurrentIndex] = useState<number>(0);
|
||||||
|
const [networkType, setNetworkType] = useState<string>('eth');
|
||||||
return (
|
return (
|
||||||
<AccountsContext.Provider
|
<AccountsContext.Provider
|
||||||
value={{ accounts, setAccounts, currentIndex, setCurrentIndex }}>
|
value={{
|
||||||
|
accounts,
|
||||||
|
setAccounts,
|
||||||
|
currentIndex,
|
||||||
|
setCurrentIndex,
|
||||||
|
networksData,
|
||||||
|
setNetworksData,
|
||||||
|
networkType,
|
||||||
|
setNetworkType,
|
||||||
|
}}>
|
||||||
{children}
|
{children}
|
||||||
</AccountsContext.Provider>
|
</AccountsContext.Provider>
|
||||||
);
|
);
|
||||||
|
146
src/screens/AddNetwork.tsx
Normal file
146
src/screens/AddNetwork.tsx
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { View } from 'react-native';
|
||||||
|
import { useForm, Controller } from 'react-hook-form';
|
||||||
|
import { TextInput, Button, HelperText } from 'react-native-paper';
|
||||||
|
|
||||||
|
import styles from '../styles/stylesheet';
|
||||||
|
import { NetworksDataState, StackParamsList } from '../types';
|
||||||
|
import { useAccounts } from '../context/AccountsContext';
|
||||||
|
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||||
|
import { useNavigation } from '@react-navigation/native';
|
||||||
|
|
||||||
|
// TODO: Add validation to form inputs
|
||||||
|
const AddNetwork = () => {
|
||||||
|
const navigation =
|
||||||
|
useNavigation<NativeStackNavigationProp<StackParamsList>>();
|
||||||
|
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
formState: { errors, isValid },
|
||||||
|
handleSubmit,
|
||||||
|
} = useForm<NetworksDataState>({
|
||||||
|
mode: 'onChange',
|
||||||
|
});
|
||||||
|
|
||||||
|
const { networksData, setNetworksData } = useAccounts();
|
||||||
|
|
||||||
|
const submit = (data: NetworksDataState) => {
|
||||||
|
setNetworksData([...networksData, data]);
|
||||||
|
navigation.navigate('Laconic');
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<View style={styles.signPage}>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
defaultValue=""
|
||||||
|
name="networkName"
|
||||||
|
render={({ field: { onChange, onBlur, value } }) => (
|
||||||
|
<>
|
||||||
|
<TextInput
|
||||||
|
mode="outlined"
|
||||||
|
label="Network Name"
|
||||||
|
value={value}
|
||||||
|
onBlur={onBlur}
|
||||||
|
onChangeText={value => onChange(value)}
|
||||||
|
/>
|
||||||
|
<HelperText type="error">{errors.networkName?.message}</HelperText>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="rpcUrl"
|
||||||
|
defaultValue=""
|
||||||
|
render={({ field: { onChange, onBlur, value } }) => (
|
||||||
|
<>
|
||||||
|
<TextInput
|
||||||
|
mode="outlined"
|
||||||
|
label="New RPC URL"
|
||||||
|
onBlur={onBlur}
|
||||||
|
value={value}
|
||||||
|
onChangeText={value => onChange(value)}
|
||||||
|
/>
|
||||||
|
<HelperText type="error">{errors.rpcUrl?.message}</HelperText>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="chainId"
|
||||||
|
defaultValue=""
|
||||||
|
render={({ field: { onChange, onBlur, value } }) => (
|
||||||
|
<>
|
||||||
|
<TextInput
|
||||||
|
mode="outlined"
|
||||||
|
value={value}
|
||||||
|
label="Chain ID"
|
||||||
|
onBlur={onBlur}
|
||||||
|
onChangeText={value => onChange(value)}
|
||||||
|
/>
|
||||||
|
<HelperText type="error">{errors.chainId?.message}</HelperText>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="currencySymbol"
|
||||||
|
defaultValue=""
|
||||||
|
render={({ field: { onChange, onBlur, value } }) => (
|
||||||
|
<>
|
||||||
|
<TextInput
|
||||||
|
mode="outlined"
|
||||||
|
value={value}
|
||||||
|
label="Currency Symbol"
|
||||||
|
onBlur={onBlur}
|
||||||
|
onChangeText={value => onChange(value)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<HelperText type="error">{errors.currencySymbol?.message}</HelperText>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
defaultValue=""
|
||||||
|
name="blockExplorerUrl"
|
||||||
|
render={({ field: { onChange, onBlur, value } }) => (
|
||||||
|
<>
|
||||||
|
<TextInput
|
||||||
|
mode="outlined"
|
||||||
|
value={value}
|
||||||
|
label="Block Explorer URL (Optional)"
|
||||||
|
onBlur={onBlur}
|
||||||
|
onChangeText={value => onChange(value)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<HelperText type="error">{errors.blockExplorerUrl?.message}</HelperText>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
// TODO: Use state to toggle between 'eth' and 'cosmos'
|
||||||
|
defaultValue="eth"
|
||||||
|
name="networkType"
|
||||||
|
render={({ field: { onBlur, value } }) => (
|
||||||
|
<>
|
||||||
|
<TextInput
|
||||||
|
mode="outlined"
|
||||||
|
value={value}
|
||||||
|
disabled
|
||||||
|
label="Block Explorer URL (Optional)"
|
||||||
|
onBlur={onBlur}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<HelperText type="error">{errors.blockExplorerUrl?.message}</HelperText>
|
||||||
|
<Button
|
||||||
|
mode="contained"
|
||||||
|
onPress={handleSubmit(submit)}
|
||||||
|
disabled={!isValid}>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddNetwork;
|
@ -25,11 +25,11 @@ import {
|
|||||||
rejectWalletConnectRequest,
|
rejectWalletConnectRequest,
|
||||||
} from '../utils/wallet-connect/WalletConnectRequests';
|
} from '../utils/wallet-connect/WalletConnectRequests';
|
||||||
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
|
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
|
||||||
import { EIP155_CHAINS } from '../utils/wallet-connect/EIP155Data';
|
|
||||||
import DataBox from '../components/DataBox';
|
import DataBox from '../components/DataBox';
|
||||||
import { getPathKey } from '../utils/misc';
|
import { getPathKey } from '../utils/misc';
|
||||||
import { COSMOS_TESTNET_CHAINS } from '../utils/wallet-connect/COSMOSData';
|
import { COSMOS_TESTNET_CHAINS } from '../utils/wallet-connect/COSMOSData';
|
||||||
import { COSMOS_DENOM } from '../utils/constants';
|
import { COSMOS_DENOM } from '../utils/constants';
|
||||||
|
import { useAccounts } from '../context/AccountsContext';
|
||||||
|
|
||||||
type SignRequestProps = NativeStackScreenProps<
|
type SignRequestProps = NativeStackScreenProps<
|
||||||
StackParamsList,
|
StackParamsList,
|
||||||
@ -37,6 +37,8 @@ type SignRequestProps = NativeStackScreenProps<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
const ApproveTransaction = ({ route }: SignRequestProps) => {
|
const ApproveTransaction = ({ route }: SignRequestProps) => {
|
||||||
|
const { networksData } = useAccounts();
|
||||||
|
|
||||||
const requestSession = route.params.requestSessionData;
|
const requestSession = route.params.requestSessionData;
|
||||||
const requestName = requestSession.peer.metadata.name;
|
const requestName = requestSession.peer.metadata.name;
|
||||||
const requestIcon = requestSession.peer.metadata.icons[0];
|
const requestIcon = requestSession.peer.metadata.icons[0];
|
||||||
@ -55,9 +57,17 @@ const ApproveTransaction = ({ route }: SignRequestProps) => {
|
|||||||
|
|
||||||
const provider = useMemo(() => {
|
const provider = useMemo(() => {
|
||||||
if (network === 'eth') {
|
if (network === 'eth') {
|
||||||
return new providers.JsonRpcProvider(EIP155_CHAINS[chainId].rpc);
|
const currentChain = networksData.find(
|
||||||
|
networkData => networkData.chainId === chainId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!currentChain) {
|
||||||
|
throw new Error('Requested chain not supported');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new providers.JsonRpcProvider(currentChain.rpcUrl);
|
||||||
}
|
}
|
||||||
}, [chainId, network]);
|
}, [chainId, network, networksData]);
|
||||||
|
|
||||||
const navigation =
|
const navigation =
|
||||||
useNavigation<NativeStackNavigationProp<StackParamsList>>();
|
useNavigation<NativeStackNavigationProp<StackParamsList>>();
|
||||||
|
@ -28,8 +28,14 @@ const WCLogo = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const HomeScreen = () => {
|
const HomeScreen = () => {
|
||||||
const { accounts, setAccounts, currentIndex, setCurrentIndex } =
|
const {
|
||||||
useAccounts();
|
accounts,
|
||||||
|
setAccounts,
|
||||||
|
currentIndex,
|
||||||
|
setCurrentIndex,
|
||||||
|
networkType,
|
||||||
|
setNetworkType,
|
||||||
|
} = useAccounts();
|
||||||
const { setActiveSessions } = useWalletConnect();
|
const { setActiveSessions } = useWalletConnect();
|
||||||
|
|
||||||
const navigation =
|
const navigation =
|
||||||
@ -54,7 +60,6 @@ const HomeScreen = () => {
|
|||||||
const [isWalletCreating, setIsWalletCreating] = useState<boolean>(false);
|
const [isWalletCreating, setIsWalletCreating] = useState<boolean>(false);
|
||||||
const [walletDialog, setWalletDialog] = useState<boolean>(false);
|
const [walletDialog, setWalletDialog] = useState<boolean>(false);
|
||||||
const [resetWalletDialog, setResetWalletDialog] = useState<boolean>(false);
|
const [resetWalletDialog, setResetWalletDialog] = useState<boolean>(false);
|
||||||
const [network, setNetwork] = useState<string>('eth');
|
|
||||||
const [isAccountsFetched, setIsAccountsFetched] = useState<boolean>(false);
|
const [isAccountsFetched, setIsAccountsFetched] = useState<boolean>(false);
|
||||||
const [phrase, setPhrase] = useState('');
|
const [phrase, setPhrase] = useState('');
|
||||||
|
|
||||||
@ -95,11 +100,11 @@ const HomeScreen = () => {
|
|||||||
setActiveSessions({});
|
setActiveSessions({});
|
||||||
|
|
||||||
hideResetDialog();
|
hideResetDialog();
|
||||||
setNetwork('eth');
|
setNetworkType('eth');
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateNetwork = (newNetwork: string) => {
|
const updateNetwork = (newNetwork: string) => {
|
||||||
setNetwork(newNetwork);
|
setNetworkType(newNetwork);
|
||||||
setCurrentIndex(0);
|
setCurrentIndex(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,12 +145,12 @@ const HomeScreen = () => {
|
|||||||
) : isWalletCreated ? (
|
) : isWalletCreated ? (
|
||||||
<>
|
<>
|
||||||
<NetworkDropdown
|
<NetworkDropdown
|
||||||
selectedNetwork={network}
|
selectedNetwork={networkType}
|
||||||
updateNetwork={updateNetwork}
|
updateNetwork={updateNetwork}
|
||||||
/>
|
/>
|
||||||
<View style={styles.accountComponent}>
|
<View style={styles.accountComponent}>
|
||||||
<Accounts
|
<Accounts
|
||||||
network={network}
|
network={networkType}
|
||||||
currentIndex={currentIndex}
|
currentIndex={currentIndex}
|
||||||
updateIndex={updateIndex}
|
updateIndex={updateIndex}
|
||||||
/>
|
/>
|
||||||
|
14
src/types.ts
14
src/types.ts
@ -22,6 +22,7 @@ export type StackParamsList = {
|
|||||||
InvalidPath: undefined;
|
InvalidPath: undefined;
|
||||||
WalletConnect: undefined;
|
WalletConnect: undefined;
|
||||||
AddSession: undefined;
|
AddSession: undefined;
|
||||||
|
AddNetwork: undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Account = {
|
export type Account = {
|
||||||
@ -46,6 +47,10 @@ export type AccountsProps = {
|
|||||||
export type NetworkDropdownProps = {
|
export type NetworkDropdownProps = {
|
||||||
selectedNetwork: string;
|
selectedNetwork: string;
|
||||||
updateNetwork: (network: string) => void;
|
updateNetwork: (network: string) => void;
|
||||||
|
customNetwork?: {
|
||||||
|
value: string;
|
||||||
|
displayName: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AccountsState = {
|
export type AccountsState = {
|
||||||
@ -53,6 +58,15 @@ export type AccountsState = {
|
|||||||
cosmosAccounts: Account[];
|
cosmosAccounts: Account[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type NetworksDataState = {
|
||||||
|
networkName: string;
|
||||||
|
rpcUrl: string;
|
||||||
|
chainId: string;
|
||||||
|
currencySymbol: string;
|
||||||
|
blockExplorerUrl?: string;
|
||||||
|
networkType: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type SignMessageParams = {
|
export type SignMessageParams = {
|
||||||
message: string;
|
message: string;
|
||||||
network: string;
|
network: string;
|
||||||
|
@ -7803,6 +7803,11 @@ react-freeze@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/react-freeze/-/react-freeze-1.0.3.tgz#5e3ca90e682fed1d73a7cb50c2c7402b3e85618d"
|
resolved "https://registry.yarnpkg.com/react-freeze/-/react-freeze-1.0.3.tgz#5e3ca90e682fed1d73a7cb50c2c7402b3e85618d"
|
||||||
integrity sha512-ZnXwLQnGzrDpHBHiC56TXFXvmolPeMjTn1UOm610M4EXGzbEDR7oOIyS2ZiItgbs6eZc4oU/a0hpk8PrcKvv5g==
|
integrity sha512-ZnXwLQnGzrDpHBHiC56TXFXvmolPeMjTn1UOm610M4EXGzbEDR7oOIyS2ZiItgbs6eZc4oU/a0hpk8PrcKvv5g==
|
||||||
|
|
||||||
|
react-hook-form@^7.51.2:
|
||||||
|
version "7.51.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.51.2.tgz#79f7f72ee217c5114ff831012d1a7ec344096e7f"
|
||||||
|
integrity sha512-y++lwaWjtzDt/XNnyGDQy6goHskFualmDlf+jzEZvjvz6KWDf7EboL7pUvRCzPTJd0EOPpdekYaQLEvvG6m6HA==
|
||||||
|
|
||||||
"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0, react-is@^18.2.0:
|
"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0, react-is@^18.2.0:
|
||||||
version "18.2.0"
|
version "18.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
||||||
|
Loading…
Reference in New Issue
Block a user