diff --git a/src/components/GlobalErrorHandler/GlobalErrorHandlerContext.tsx b/src/components/GlobalErrorHandler/GlobalErrorHandlerContext.tsx index 37ec6894e..677382a4d 100644 --- a/src/components/GlobalErrorHandler/GlobalErrorHandlerContext.tsx +++ b/src/components/GlobalErrorHandler/GlobalErrorHandlerContext.tsx @@ -14,7 +14,7 @@ interface GlobalErrorHandlerProviderType { GlobalErrorHandlerViewComp?: FC } -const GlobalErrorHandlerContext = createContext({ +export const GlobalErrorHandlerContext = createContext({ setGlobalError: () => {}, globalError: null, handleReload: () => {}, diff --git a/src/core/CoreWithStore.tsx b/src/core/CoreWithStore.tsx index 8a00d742f..94dff3a65 100644 --- a/src/core/CoreWithStore.tsx +++ b/src/core/CoreWithStore.tsx @@ -1,14 +1,18 @@ import { Provider } from 'react-redux' import { PersistGate } from 'redux-persist/integration/react' -import { store, persistor } from 'store/store' +import { createNewStore } from 'store/store' import { Core } from './Core' -export const CoreWithStore = () => ( - - - - - -) +export const CoreWithStore = () => { + const { store, persistor } = createNewStore() + + return ( + + + + + + ) +} diff --git a/src/redux/rootReducer.ts b/src/redux/rootReducer.ts index fe7adb0a7..e2f908208 100644 --- a/src/redux/rootReducer.ts +++ b/src/redux/rootReducer.ts @@ -4,6 +4,7 @@ import { persistReducer, createMigrate, PersistConfig } from 'redux-persist' import { reduxStorage } from 'storage/ReduxStorage' import { contactsReducer } from 'store/slices/contactsSlice' import { ProfileStatus } from 'navigation/profileNavigator/types' +import { getCurrentChainId } from 'storage/ChainStorage' import { accountsReducer } from './slices/accountsSlice' import { balancesReducer } from './slices/balancesSlice' @@ -28,35 +29,37 @@ const migrations = { }), } -const settingsPersistConfig: PersistConfig = { - key: 'settings', - whitelist: ['pin', 'chainId', 'isFirstLaunch', 'usedBitcoinAddresses'], - storage: reduxStorage, -} +export const createRootReducer = () => { + const settingsPersistConfig: PersistConfig = { + key: 'settings', + whitelist: ['pin', 'chainId', 'isFirstLaunch', 'usedBitcoinAddresses'], + storage: reduxStorage(getCurrentChainId()), + } -const rootPersistConfig = { - key: 'root', - storage: reduxStorage, - version: 0, - migrate: createMigrate(migrations), - whitelist: [ - 'profile', - 'accounts', - 'contacts', - 'balances', - 'usdPrices', - 'transactions', - ], -} + const rootPersistConfig = { + key: 'root', + version: 0, + migrate: createMigrate(migrations), + whitelist: [ + 'profile', + 'accounts', + 'contacts', + 'balances', + 'usdPrices', + 'transactions', + ], + storage: reduxStorage(getCurrentChainId()), + } -const reducers = combineReducers({ - usdPrices: usdPriceReducer, - balances: balancesReducer, - transactions: transactionsReducer, - settings: persistReducer(settingsPersistConfig, settingsSliceReducer), - profile: profileReducer, - accounts: accountsReducer, - contacts: contactsReducer, -}) + const reducers = combineReducers({ + usdPrices: usdPriceReducer, + balances: balancesReducer, + transactions: transactionsReducer, + settings: persistReducer(settingsPersistConfig, settingsSliceReducer), + profile: profileReducer, + accounts: accountsReducer, + contacts: contactsReducer, + }) -export const rootReducer = persistReducer(rootPersistConfig, reducers) + return persistReducer(rootPersistConfig, reducers) +} diff --git a/src/redux/slices/settingsSlice/index.ts b/src/redux/slices/settingsSlice/index.ts index 477e75154..9626f7a3c 100644 --- a/src/redux/slices/settingsSlice/index.ts +++ b/src/redux/slices/settingsSlice/index.ts @@ -25,7 +25,11 @@ import { SocketsEvents, socketsEvents, } from 'src/subscriptions/rifSockets' -import { ChainTypesByIdType } from 'shared/constants/chainConstants' +import { + chainTypesById, + ChainTypesByIdType, +} from 'shared/constants/chainConstants' +import { getCurrentChainId } from 'storage/ChainStorage' import { Bitcoin, @@ -322,7 +326,11 @@ const initialState: SettingsSlice = { const settingsSlice = createSlice({ name: 'settings', - initialState, + initialState: () => ({ + ...initialState, + chainId: getCurrentChainId(), + chainType: chainTypesById[getCurrentChainId()], + }), reducers: { setIsFirstLaunch: (state, { payload }: PayloadAction) => { state.isFirstLaunch = payload diff --git a/src/redux/store.ts b/src/redux/store.ts index b39d0e379..911b5047b 100644 --- a/src/redux/store.ts +++ b/src/redux/store.ts @@ -10,13 +10,13 @@ import { // REGISTER, } from 'redux-persist' -import { rootReducer } from './rootReducer' +import { createRootReducer } from './rootReducer' // Must use redux-debugger plugin in flipper for the redux debugger to work export const createStore = (preloadedState = {}) => configureStore({ - reducer: rootReducer, + reducer: createRootReducer(), preloadedState, middleware: getDefaultMiddlewares => { const middlewares = getDefaultMiddlewares({ @@ -31,8 +31,14 @@ export const createStore = (preloadedState = {}) => export const store = createStore() -export const persistor = persistStore(store) - +export const createNewStore = () => { + const newStore = createStore() + const newPersistor = persistStore(newStore) + return { + store: newStore, + persistor: newPersistor, + } +} // Infer the `RootState` and `AppDispatch` types from the store itself export type RootState = ReturnType // Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState} diff --git a/src/screens/settings/SettingsScreen.tsx b/src/screens/settings/SettingsScreen.tsx index 02f6e88d5..da77c488c 100644 --- a/src/screens/settings/SettingsScreen.tsx +++ b/src/screens/settings/SettingsScreen.tsx @@ -1,5 +1,5 @@ import { version } from 'package.json' -import { useCallback, useEffect, useMemo } from 'react' +import { useCallback, useContext, useEffect, useMemo } from 'react' import { useTranslation } from 'react-i18next' import { Platform, ScrollView, StyleSheet, View } from 'react-native' @@ -15,17 +15,21 @@ import { sharedColors, sharedStyles } from 'shared/constants' import { castStyle } from 'shared/utils' import { selectChainId, + selectChainType, selectPin, selectWalletIsDeployed, } from 'store/slices/settingsSlice' import { useAppSelector } from 'store/storeUtils' -import { chainTypesById } from 'shared/constants/chainConstants' +import { ChainTypeEnum, chainTypesById } from 'shared/constants/chainConstants' +import { GlobalErrorHandlerContext } from 'components/GlobalErrorHandler/GlobalErrorHandlerContext' +import { getCurrentChainId, setCurrentChainId } from 'storage/ChainStorage' export const SettingsScreen = ({ navigation, }: SettingsScreenProps) => { const statePIN = useAppSelector(selectPin) const chainId = useAppSelector(selectChainId) + const chainType = useAppSelector(selectChainType) const walletIsDeployed = useAppSelector(selectWalletIsDeployed) const smartWalletFactoryAddress = useMemo( @@ -78,6 +82,12 @@ export const SettingsScreen = ({ }, [navigation]) const { t } = useTranslation() + const { handleReload } = useContext(GlobalErrorHandlerContext) + const onSwitchChains = () => { + const currentChainId = getCurrentChainId() + setCurrentChainId(currentChainId === 31 ? 30 : 31) + handleReload() + } return ( @@ -129,6 +139,18 @@ export const SettingsScreen = ({ )} + + + Switch to{' '} + {chainType === ChainTypeEnum.MAINNET + ? ChainTypeEnum.TESTNET + : ChainTypeEnum.MAINNET} + + ChainTypesByIdType = () => + MainStorage.get('chainId') || 31 + +export const setCurrentChainId = (chainId: ChainTypesByIdType) => + MainStorage.set('chainId', chainId) diff --git a/src/storage/ReduxStorage.ts b/src/storage/ReduxStorage.ts index 2ffef08cf..c9ba4f257 100644 --- a/src/storage/ReduxStorage.ts +++ b/src/storage/ReduxStorage.ts @@ -4,17 +4,50 @@ import { MMKVStorage } from './MMKVStorage' const storage = new MMKVStorage() -export const reduxStorage: Storage = { +export const reduxStorage: (chainId: number) => Storage = ( + chainId: number, +) => ({ setItem: (key, value) => { - storage.set(key, value) + const keyToUse = `${key}_${chainId}` + if (chainId === 31) { + storage.set(key, value) + } + storage.set(keyToUse, value) return Promise.resolve(true) }, getItem: key => { - const value = storage.get(key) + let keyToUse = `${key}_${chainId}` + if (chainId === 31) { + keyToUse = key + } + const value = storage.get(keyToUse) return Promise.resolve(value) }, removeItem: key => { - storage.delete(key) + const keyToUse = `${key}_${chainId}` + if (chainId === 31) { + storage.delete(key) + } + storage.delete(keyToUse) return Promise.resolve() }, -} +}) + +// Incremental rollout - uncomment this and remove code above after 1 month (due date: 12 Oct 2023) +/* +export const reduxStorage: (chainId: number) => Storage = ( + chainId: number, +) => ({ + setItem: (key, value) => { + storage.set(`${key}_${chainId}`, value) + return Promise.resolve(true) + }, + getItem: key => { + const value = storage.get(`${key}_${chainId}`) + return Promise.resolve(value) + }, + removeItem: key => { + storage.delete(`${key}_${chainId}`) + return Promise.resolve() + }, +})*/ diff --git a/src/subscriptions/rifSockets.ts b/src/subscriptions/rifSockets.ts index 6fe0a2ee1..98dcbf885 100644 --- a/src/subscriptions/rifSockets.ts +++ b/src/subscriptions/rifSockets.ts @@ -84,6 +84,10 @@ export const rifSockets = ({ currentInstance.cache = new MMKVStorage('txs', encryptionKey) }, }, + { + cacheBlockNumberText: `blockNumber_${chainId}`, + cacheTxsText: `cachedTxs_${chainId}`, + }, ) const connectSocket = () => {