From 94bd8b6480a5c75b5334cd7c30210bbc19c448b3 Mon Sep 17 00:00:00 2001
From: IshaVenikar <145848618+IshaVenikar@users.noreply.github.com>
Date: Wed, 10 Apr 2024 15:15:51 +0530
Subject: [PATCH] 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
---
index.js | 17 ++++---
src/components/Accounts.tsx | 4 +-
src/components/NetworkDropdown.tsx | 4 +-
src/components/PairingModal.tsx | 5 ++-
src/context/AccountsContext.tsx | 37 +---------------
src/context/NetworksContext.tsx | 71 ++++++++++++++++++++++++++++++
src/screens/AddNetwork.tsx | 11 +++--
src/screens/ApproveTransaction.tsx | 24 +++++++---
src/screens/HomeScreen.tsx | 6 +--
src/screens/SignRequest.tsx | 5 ++-
src/types.ts | 1 +
src/utils/accounts.ts | 34 +++++++++++++-
src/utils/constants.ts | 23 ++++++++++
13 files changed, 178 insertions(+), 64 deletions(-)
create mode 100644 src/context/NetworksContext.tsx
create mode 100644 src/utils/constants.ts
diff --git a/index.js b/index.js
index 5a8a4aa..e160e8c 100644
--- a/index.js
+++ b/index.js
@@ -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 (
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
);
}
diff --git a/src/components/Accounts.tsx b/src/components/Accounts.tsx
index 13cb6fd..a55e639 100644
--- a/src/components/Accounts.tsx
+++ b/src/components/Accounts.tsx
@@ -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>();
- 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);
diff --git a/src/components/NetworkDropdown.tsx b/src/components/NetworkDropdown.tsx
index cc5d329..adabc58 100644
--- a/src/components/NetworkDropdown.tsx
+++ b/src/components/NetworkDropdown.tsx
@@ -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(false);
const [selectedNetwork, setSelectedNetwork] = useState(
diff --git a/src/components/PairingModal.tsx b/src/components/PairingModal.tsx
index fdf849c..7781092 100644
--- a/src/components/PairingModal.tsx
+++ b/src/components/PairingModal.tsx
@@ -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;
diff --git a/src/context/AccountsContext.tsx b/src/context/AccountsContext.tsx
index b97e3a6..f0edd2c 100644
--- a/src/context/AccountsContext.tsx
+++ b/src/context/AccountsContext.tsx
@@ -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([
- {
- 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(0);
const [networkType, setNetworkType] = useState('eth');
- const [currentChainId, setCurrentChainId] = useState(
- networksData[0].chainId,
- );
return (
{
setAccounts,
currentIndex,
setCurrentIndex,
- networksData,
- setNetworksData,
networkType,
setNetworkType,
- currentChainId,
- setCurrentChainId,
}}>
{children}
diff --git a/src/context/NetworksContext.tsx b/src/context/NetworksContext.tsx
new file mode 100644
index 0000000..79af79d
--- /dev/null
+++ b/src/context/NetworksContext.tsx
@@ -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>;
+ 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([]);
+ const [currentIndex, setCurrentIndex] = useState(0);
+ const [networkType, setNetworkType] = useState('eth');
+ const [currentChainId, setCurrentChainId] = useState();
+
+ 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 (
+
+ {children}
+
+ );
+};
+
+export { useNetworks, NetworksProvider };
diff --git a/src/screens/AddNetwork.tsx b/src/screens/AddNetwork.tsx
index 3121b72..fa413c6 100644
--- a/src/screens/AddNetwork.tsx
+++ b/src/screens/AddNetwork.tsx
@@ -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('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');
},
diff --git a/src/screens/ApproveTransaction.tsx b/src/screens/ApproveTransaction.tsx
index a080c19..ae20a9d 100644
--- a/src/screens/ApproveTransaction.tsx
+++ b/src/screens/ApproveTransaction.tsx
@@ -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) => {
{transaction && (
{network === 'eth' && (
diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx
index 678ab5d..ccf4909 100644
--- a/src/screens/HomeScreen.tsx
+++ b/src/screens/HomeScreen.tsx
@@ -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 =
diff --git a/src/screens/SignRequest.tsx b/src/screens/SignRequest.tsx
index 5dd60be..5a7ccc0 100644
--- a/src/screens/SignRequest.tsx
+++ b/src/screens/SignRequest.tsx
@@ -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;
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,
diff --git a/src/types.ts b/src/types.ts
index 2f17e30..b632815 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -63,6 +63,7 @@ export type NetworksDataState = {
nativeDenom?: string;
addressPrefix?: string;
coinType?: string;
+ isDefault: boolean;
};
export type SignMessageParams = {
diff --git a/src/utils/accounts.ts b/src/utils/accounts.ts
index 7bdf899..168aed9 100644
--- a/src/utils/accounts.ts
+++ b/src/utils/accounts.ts
@@ -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 => {
+ 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 => {
+ 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,
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
new file mode 100644
index 0000000..19e7f6f
--- /dev/null
+++ b/src/utils/constants.ts
@@ -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,
+ },
+];