forked from cerc-io/laconic-wallet
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:
parent
23fa5415ae
commit
94bd8b6480
17
index.js
17
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 (
|
||||
<PaperProvider theme={'light'}>
|
||||
<AccountsProvider>
|
||||
<WalletConnectProvider>
|
||||
<NavigationContainer linking={linking}>
|
||||
<App />
|
||||
</NavigationContainer>
|
||||
</WalletConnectProvider>
|
||||
</AccountsProvider>
|
||||
<NetworksProvider>
|
||||
<AccountsProvider>
|
||||
<WalletConnectProvider>
|
||||
<NavigationContainer linking={linking}>
|
||||
<App />
|
||||
</NavigationContainer>
|
||||
</WalletConnectProvider>
|
||||
</AccountsProvider>
|
||||
</NetworksProvider>
|
||||
</PaperProvider>
|
||||
);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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>(
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
71
src/context/NetworksContext.tsx
Normal file
71
src/context/NetworksContext.tsx
Normal 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 };
|
@ -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');
|
||||
},
|
||||
|
@ -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' && (
|
||||
|
@ -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 =
|
||||
|
@ -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,
|
||||
|
@ -63,6 +63,7 @@ export type NetworksDataState = {
|
||||
nativeDenom?: string;
|
||||
addressPrefix?: string;
|
||||
coinType?: string;
|
||||
isDefault: boolean;
|
||||
};
|
||||
|
||||
export type SignMessageParams = {
|
||||
|
@ -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
23
src/utils/constants.ts
Normal 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,
|
||||
},
|
||||
];
|
Loading…
Reference in New Issue
Block a user