Persist network data (#84)

* Store new network data

* Store default networks in keystore (#86)

* Add default nws in keystore

* Fix duplicate networks

* Display correct currency symbols for eth and cosmos tx

* Fix currency display

* Use wei for eth
This commit is contained in:
IshaVenikar 2024-04-10 15:15:51 +05:30 committed by Nabarun Gogoi
parent 23fa5415ae
commit 94bd8b6480
13 changed files with 178 additions and 64 deletions

View File

@ -7,6 +7,7 @@ import { NavigationContainer } from '@react-navigation/native';
import App from './src/App';
import { AccountsProvider } from './src/context/AccountsContext';
import { NetworksProvider } from './src/context/NetworksContext';
import { WalletConnectProvider } from './src/context/WalletConnectContext';
import { name as appName } from './app.json';
@ -23,13 +24,15 @@ export default function Main() {
};
return (
<PaperProvider theme={'light'}>
<AccountsProvider>
<WalletConnectProvider>
<NavigationContainer linking={linking}>
<App />
</NavigationContainer>
</WalletConnectProvider>
</AccountsProvider>
<NetworksProvider>
<AccountsProvider>
<WalletConnectProvider>
<NavigationContainer linking={linking}>
<App />
</NavigationContainer>
</WalletConnectProvider>
</AccountsProvider>
</NetworksProvider>
</PaperProvider>
);
}

View File

@ -15,6 +15,7 @@ import { useAccounts } from '../context/AccountsContext';
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
import { EIP155_SIGNING_METHODS } from '../utils/wallet-connect/EIP155Data';
import { COSMOS_METHODS } from '../utils/wallet-connect/COSMOSData';
import { useNetworks } from '../context/NetworksContext';
const Accounts = ({
network,
@ -24,7 +25,8 @@ const Accounts = ({
const navigation =
useNavigation<NativeStackNavigationProp<StackParamsList>>();
const { accounts, setAccounts, networksData, currentChainId } = useAccounts();
const { accounts, setAccounts } = useAccounts();
const { networksData, currentChainId } = useNetworks();
const [expanded, setExpanded] = useState(false);
const [isAccountCreating, setIsAccountCreating] = useState(false);
const [hdDialog, setHdDialog] = useState(false);

View File

@ -4,10 +4,10 @@ import { List } from 'react-native-paper';
import { NetworkDropdownProps, NetworksDataState } from '../types';
import styles from '../styles/stylesheet';
import { useAccounts } from '../context/AccountsContext';
import { useNetworks } from '../context/NetworksContext';
const NetworkDropdown = ({ updateNetwork }: NetworkDropdownProps) => {
const { networksData } = useAccounts();
const { networksData } = useNetworks();
const [expanded, setExpanded] = useState<boolean>(false);
const [selectedNetwork, setSelectedNetwork] = useState<string>(

View File

@ -13,6 +13,7 @@ import { useAccounts } from '../context/AccountsContext';
import { useWalletConnect } from '../context/WalletConnectContext';
import { EIP155_SIGNING_METHODS } from '../utils/wallet-connect/EIP155Data';
import { COSMOS_METHODS } from '../utils/wallet-connect/COSMOSData';
import { useNetworks } from '../context/NetworksContext';
const PairingModal = ({
visible,
@ -21,8 +22,8 @@ const PairingModal = ({
setModalVisible,
setToastVisible,
}: PairingModalProps) => {
const { accounts, networksData, currentChainId, currentIndex } =
useAccounts();
const { accounts, currentIndex } = useAccounts();
const { networksData, currentChainId } = useNetworks();
const [isLoading, setIsLoading] = useState(false);
const dappName = currentProposal?.params?.proposer?.metadata.name;

View File

@ -1,31 +1,21 @@
import React, { createContext, useContext, useState } from 'react';
import { AccountsState, NetworksDataState } from '../types';
import { EIP155_CHAINS } from '../utils/wallet-connect/EIP155Data';
import { COSMOS_TESTNET_CHAINS } from '../utils/wallet-connect/COSMOSData';
import { AccountsState } from '../types';
const AccountsContext = createContext<{
accounts: AccountsState;
setAccounts: (account: AccountsState) => void;
currentIndex: number;
setCurrentIndex: (index: number) => void;
networksData: NetworksDataState[];
setNetworksData: (networksDataArray: NetworksDataState[]) => void;
networkType: string;
setNetworkType: (networkType: string) => void;
currentChainId: string;
setCurrentChainId: (currentChainId: string) => void;
}>({
accounts: { ethAccounts: [], cosmosAccounts: [] },
setAccounts: () => {},
currentIndex: 0,
setCurrentIndex: () => {},
networksData: [],
setNetworksData: () => {},
networkType: '',
setNetworkType: () => {},
currentChainId: '',
setCurrentChainId: () => {},
});
const useAccounts = () => {
@ -38,29 +28,8 @@ const AccountsProvider = ({ children }: { children: any }) => {
ethAccounts: [],
cosmosAccounts: [],
});
const [networksData, setNetworksData] = useState<NetworksDataState[]>([
{
chainId: 'eip155:1',
networkName: EIP155_CHAINS['eip155:1'].name,
networkType: 'eth',
rpcUrl: EIP155_CHAINS['eip155:1'].rpc,
currencySymbol: 'ETH',
},
{
chainId: 'cosmos:theta-testnet-001',
networkName: COSMOS_TESTNET_CHAINS['cosmos:theta-testnet-001'].name,
networkType: 'cosmos',
rpcUrl: COSMOS_TESTNET_CHAINS['cosmos:theta-testnet-001'].rpc,
nativeDenom: 'uatom',
addressPrefix: 'cosmos',
coinType: '118',
},
]);
const [currentIndex, setCurrentIndex] = useState<number>(0);
const [networkType, setNetworkType] = useState<string>('eth');
const [currentChainId, setCurrentChainId] = useState<string>(
networksData[0].chainId,
);
return (
<AccountsContext.Provider
@ -69,12 +38,8 @@ const AccountsProvider = ({ children }: { children: any }) => {
setAccounts,
currentIndex,
setCurrentIndex,
networksData,
setNetworksData,
networkType,
setNetworkType,
currentChainId,
setCurrentChainId,
}}>
{children}
</AccountsContext.Provider>

View File

@ -0,0 +1,71 @@
import React, { createContext, useContext, useEffect, useState } from 'react';
import { NetworksDataState } from '../types';
import { retrieveNetworksData, storeNetworkData } from '../utils/accounts';
import { DEFAULTNETWORKS } from '../utils/constants';
const NetworksContext = createContext<{
currentIndex: number;
setCurrentIndex: (index: number) => void;
networksData: NetworksDataState[];
setNetworksData: React.Dispatch<React.SetStateAction<NetworksDataState[]>>;
networkType: string;
setNetworkType: (networkType: string) => void;
currentChainId?: string;
setCurrentChainId: (currentChainId: string) => void;
}>({
currentIndex: 0,
setCurrentIndex: () => {},
networksData: [],
setNetworksData: () => {},
networkType: '',
setNetworkType: () => {},
currentChainId: undefined,
setCurrentChainId: () => {},
});
const useNetworks = () => {
const networksContext = useContext(NetworksContext);
return networksContext;
};
const NetworksProvider = ({ children }: { children: any }) => {
const [networksData, setNetworksData] = useState<NetworksDataState[]>([]);
const [currentIndex, setCurrentIndex] = useState<number>(0);
const [networkType, setNetworkType] = useState<string>('eth');
const [currentChainId, setCurrentChainId] = useState<string>();
useEffect(() => {
const fetchData = async () => {
const retrievedNetworks = await retrieveNetworksData();
if (retrievedNetworks.length === 0) {
for (const defaultNetwork of DEFAULTNETWORKS) {
await storeNetworkData(defaultNetwork);
}
}
const retrievedNewNetworks = await retrieveNetworksData();
setNetworksData(retrievedNewNetworks);
setCurrentChainId(retrievedNewNetworks[0].chainId);
};
fetchData();
}, []);
return (
<NetworksContext.Provider
value={{
currentIndex,
setCurrentIndex,
networksData,
setNetworksData,
networkType,
setNetworkType,
currentChainId,
setCurrentChainId,
}}>
{children}
</NetworksContext.Provider>
);
};
export { useNetworks, NetworksProvider };

View File

@ -8,8 +8,9 @@ import { useNavigation } from '@react-navigation/native';
import styles from '../styles/stylesheet';
import { NetworksDataState, StackParamsList } from '../types';
import { useAccounts } from '../context/AccountsContext';
import { SelectNetworkType } from '../components/SelectNetworkType';
import { storeNetworkData } from '../utils/accounts';
import { useNetworks } from '../context/NetworksContext';
// TODO: Add validation to form inputs
const AddNetwork = () => {
@ -24,7 +25,7 @@ const AddNetwork = () => {
mode: 'onChange',
});
const { networksData, setNetworksData } = useAccounts();
const { networksData, setNetworksData } = useNetworks();
const [networkType, setNetworkType] = useState<string>('eth');
@ -35,12 +36,14 @@ const AddNetwork = () => {
const submit = useCallback(
async (data: NetworksDataState) => {
const namespace = networkType === 'eth' ? 'eip155:' : 'cosmos:';
const updatedData = {
const newNetworkData = {
...data,
chainId: `${namespace}${data.chainId}`,
networkType,
isDefault: false,
};
setNetworksData([...networksData, updatedData]);
setNetworksData([...networksData, newNetworkData]);
await storeNetworkData(newNetworkData);
navigation.navigate('Laconic');
},

View File

@ -27,7 +27,7 @@ import {
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
import DataBox from '../components/DataBox';
import { getPathKey } from '../utils/misc';
import { useAccounts } from '../context/AccountsContext';
import { useNetworks } from '../context/NetworksContext';
type SignRequestProps = NativeStackScreenProps<
StackParamsList,
@ -35,7 +35,7 @@ type SignRequestProps = NativeStackScreenProps<
>;
const ApproveTransaction = ({ route }: SignRequestProps) => {
const { networksData } = useAccounts();
const { networksData } = useNetworks();
const requestSession = route.params.requestSessionData;
const requestName = requestSession.peer.metadata.name;
@ -239,24 +239,36 @@ const ApproveTransaction = ({ route }: SignRequestProps) => {
</View>
</View>
<DataBox
label={`Balance ${requestedChain!.nativeDenom!}`}
label={`Balance (${
requestedChain!.networkType === 'eth'
? 'wei'
: requestedChain!.nativeDenom
}`}
data={
balance === '' || balance === undefined
? 'Loading balance...'
: `${balance}`
: `${balance})`
}
/>
{transaction && (
<View style={styles.approveTransaction}>
<DataBox label="To" data={transaction.to!} />
<DataBox
label={`Amount ${requestedChain!.nativeDenom!}`}
label={`Amount (${
requestedChain!.networkType === 'eth'
? 'wei'
: requestedChain!.nativeDenom
})`}
data={BigNumber.from(
transaction.value?.toString(),
).toString()}
/>
<DataBox
label={`Gas Fees ${requestedChain!.nativeDenom!}`}
label={`Gas Fees (${
requestedChain!.networkType === 'eth'
? 'wei'
: requestedChain!.nativeDenom
})`}
data={gasFees!}
/>
{network === 'eth' && (

View File

@ -17,6 +17,7 @@ import { useAccounts } from '../context/AccountsContext';
import { useWalletConnect } from '../context/WalletConnectContext';
import { NetworksDataState, StackParamsList } from '../types';
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
import { useNetworks } from '../context/NetworksContext';
const WCLogo = () => {
return (
@ -35,10 +36,9 @@ const HomeScreen = () => {
setCurrentIndex,
networkType,
setNetworkType,
networksData,
currentChainId,
setCurrentChainId,
} = useAccounts();
const { networksData, currentChainId, setCurrentChainId } = useNetworks();
const { setActiveSessions } = useWalletConnect();
const navigation =

View File

@ -21,12 +21,12 @@ import {
} from '../utils/wallet-connect/WalletConnectRequests';
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
import { EIP155_SIGNING_METHODS } from '../utils/wallet-connect/EIP155Data';
import { useAccounts } from '../context/AccountsContext';
import { useNetworks } from '../context/NetworksContext';
type SignRequestProps = NativeStackScreenProps<StackParamsList, 'SignRequest'>;
const SignRequest = ({ route }: SignRequestProps) => {
const { networksData } = useAccounts();
const { networksData } = useNetworks();
const requestSession = route.params.requestSessionData;
const requestName = requestSession?.peer?.metadata?.name;
@ -152,6 +152,7 @@ const SignRequest = ({ route }: SignRequestProps) => {
}
const response = await approveWalletConnectRequest(
networksData,
requestEvent,
account,
network,

View File

@ -63,6 +63,7 @@ export type NetworksDataState = {
nativeDenom?: string;
addressPrefix?: string;
coinType?: string;
isDefault: boolean;
};
export type SignMessageParams = {

View File

@ -16,7 +16,7 @@ import { Secp256k1HdWallet } from '@cosmjs/amino';
import { AccountData } from '@cosmjs/proto-signing';
import { stringToPath } from '@cosmjs/crypto';
import { Account, WalletDetails } from '../types';
import { Account, NetworksDataState, WalletDetails } from '../types';
import {
getHDPath,
getPathKey,
@ -124,6 +124,36 @@ const addAccountFromHDPath = async (
}
};
const storeNetworkData = async (
networkData: NetworksDataState,
): Promise<void> => {
const networks = await getInternetCredentials('networks');
const retrievedNetworks =
networks && networks.password ? JSON.parse(networks.password) : [];
let networkId = 0;
if (retrievedNetworks.length > 0) {
networkId = retrievedNetworks[retrievedNetworks.length - 1].networkId + 1;
}
const updatedNetworks = [
...retrievedNetworks,
{ networkId: networkId, ...networkData },
];
await setInternetCredentials(
'networks',
'_',
JSON.stringify(updatedNetworks),
);
};
const retrieveNetworksData = async (): Promise<NetworksDataState[]> => {
const networks = await getInternetCredentials('networks');
const retrievedNetworks: NetworksDataState[] =
networks && networks.password ? JSON.parse(networks.password) : [];
return retrievedNetworks;
};
export const retrieveAccountsForNetwork = async (
network: string,
accountsIndices: string,
@ -318,6 +348,8 @@ export {
createWallet,
addAccount,
addAccountFromHDPath,
storeNetworkData,
retrieveNetworksData,
retrieveAccounts,
retrieveSingleAccount,
resetWallet,

23
src/utils/constants.ts Normal file
View File

@ -0,0 +1,23 @@
import { COSMOS_TESTNET_CHAINS } from './wallet-connect/COSMOSData';
import { EIP155_CHAINS } from './wallet-connect/EIP155Data';
export const DEFAULTNETWORKS = [
{
chainId: 'eip155:1',
networkName: EIP155_CHAINS['eip155:1'].name,
networkType: 'eth',
rpcUrl: EIP155_CHAINS['eip155:1'].rpc,
currencySymbol: 'ETH',
isDefault: true,
},
{
chainId: 'cosmos:theta-testnet-001',
networkName: COSMOS_TESTNET_CHAINS['cosmos:theta-testnet-001'].name,
networkType: 'cosmos',
rpcUrl: COSMOS_TESTNET_CHAINS['cosmos:theta-testnet-001'].rpc,
nativeDenom: 'uatom',
addressPrefix: 'cosmos',
coinType: '118',
isDefault: true,
},
];