diff --git a/lib/types/crypto-types.js b/lib/types/crypto-types.js
index d0184519d..ef86f5943 100644
--- a/lib/types/crypto-types.js
+++ b/lib/types/crypto-types.js
@@ -1,75 +1,75 @@
 // @flow
 
 import t, { type TInterface } from 'tcomb';
 
 import { tShape } from '../utils/validation-utils.js';
 
 export type OLMIdentityKeys = {
   +ed25519: string,
   +curve25519: string,
 };
 
 export type OLMPrekey = {
   +curve25519: {
     +id: string,
     +key: string,
   },
 };
 
 export type OLMOneTimeKeys = {
   +curve25519: { +[string]: string },
 };
 
 export type PickledOLMAccount = {
   +picklingKey: string,
   +pickledAccount: string,
 };
 
 export type CryptoStore = {
-  +primaryAccount: ?PickledOLMAccount,
-  +primaryIdentityKeys: ?OLMIdentityKeys,
-  +notificationAccount: ?PickledOLMAccount,
-  +notificationIdentityKeys: ?OLMIdentityKeys,
+  +primaryAccount: PickledOLMAccount,
+  +primaryIdentityKeys: OLMIdentityKeys,
+  +notificationAccount: PickledOLMAccount,
+  +notificationIdentityKeys: OLMIdentityKeys,
 };
 
 export type IdentityKeysBlob = {
   +primaryIdentityPublicKeys: OLMIdentityKeys,
   +notificationIdentityPublicKeys: OLMIdentityKeys,
 };
 
 export type SignedIdentityKeysBlob = {
   +payload: string,
   +signature: string,
 };
 export const signedIdentityKeysBlobValidator: TInterface<SignedIdentityKeysBlob> =
   tShape<SignedIdentityKeysBlob>({
     payload: t.String,
     signature: t.String,
   });
 
 // This type should not be changed without making equivalent changes to
 // `Message` in Identity service's `reserved_users` module
 export type ReservedUsernameMessage =
   | {
       +statement: 'Add the following usernames to reserved list',
       +payload: $ReadOnlyArray<string>,
       +issuedAt: string,
     }
   | {
       +statement: 'Remove the following username from reserved list',
       +payload: string,
       +issuedAt: string,
     }
   | {
       +statement: 'This user is the owner of the following username and user ID',
       +payload: {
         +username: string,
         +userID: string,
       },
       +issuedAt: string,
     };
 
 export const olmEncryptedMessageTypes = Object.freeze({
   PREKEY: 0,
   TEXT: 1,
 });
diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js
index 3947c5888..736468fc5 100644
--- a/lib/types/redux-types.js
+++ b/lib/types/redux-types.js
@@ -1,1266 +1,1266 @@
 // @flow
 
 import type {
   LogOutResult,
   LogInStartingPayload,
   LogInResult,
   RegisterResult,
   DefaultNotificationPayload,
   ClaimUsernameResponse,
 } from './account-types.js';
 import type {
   ActivityUpdateSuccessPayload,
   QueueActivityUpdatesPayload,
   SetThreadUnreadStatusPayload,
 } from './activity-types.js';
 import type {
   UpdateUserAvatarRequest,
   UpdateUserAvatarResponse,
 } from './avatar-types.js';
 import type { CryptoStore } from './crypto-types.js';
 import type {
   GetVersionActionPayload,
   LastCommunicatedPlatformDetails,
 } from './device-types.js';
 import type { ClientDBDraftInfo, DraftStore } from './draft-types.js';
 import type { EnabledApps, SupportedApps } from './enabled-apps.js';
 import type {
   RawEntryInfo,
   EntryStore,
   SaveEntryPayload,
   CreateEntryPayload,
   DeleteEntryResult,
   RestoreEntryPayload,
   FetchEntryInfosResult,
   CalendarQueryUpdateResult,
   CalendarQueryUpdateStartingPayload,
   CalendarQuery,
 } from './entry-types.js';
 import type {
   CalendarFilter,
   CalendarThreadFilter,
   SetCalendarDeletedFilterPayload,
 } from './filter-types.js';
 import type { IntegrityStore } from './integrity-types.js';
 import type {
   KeyserverStore,
   AddKeyserverPayload,
   RemoveKeyserverPayload,
 } from './keyserver-types.js';
 import type { LifecycleState } from './lifecycle-state-types.js';
 import type {
   FetchInviteLinksResponse,
   InviteLink,
   InviteLinksStore,
   InviteLinkVerificationResponse,
   DisableInviteLinkPayload,
 } from './link-types.js';
 import type { LoadingStatus, LoadingInfo } from './loading-types.js';
 import type { UpdateMultimediaMessageMediaPayload } from './media-types.js';
 import type { MessageReportCreationResult } from './message-report-types.js';
 import type {
   MessageStore,
   RawMultimediaMessageInfo,
   FetchMessageInfosPayload,
   SendMessagePayload,
   EditMessagePayload,
   SaveMessagesPayload,
   NewMessagesPayload,
   MessageStorePrunePayload,
   LocallyComposedMessageInfo,
   ClientDBMessageInfo,
   SimpleMessagesPayload,
   ClientDBThreadMessageInfo,
   FetchPinnedMessagesResult,
   SearchMessagesResponse,
 } from './message-types.js';
 import type { RawReactionMessageInfo } from './messages/reaction.js';
 import type { RawTextMessageInfo } from './messages/text.js';
 import type { BaseNavInfo } from './nav-types.js';
 import {
   type ForcePolicyAcknowledgmentPayload,
   type PolicyAcknowledgmentPayload,
   type UserPolicies,
 } from './policy-types.js';
 import type { RelationshipErrors } from './relationship-types.js';
 import type {
   EnabledReports,
   ClearDeliveredReportsPayload,
   QueueReportsPayload,
   ReportStore,
   ClientReportCreationRequest,
 } from './report-types.js';
 import type {
   ProcessServerRequestAction,
   GetOlmSessionInitializationDataResponse,
 } from './request-types.js';
 import type {
   UserSearchResult,
   ExactUserSearchResult,
 } from './search-types.js';
 import type { SetSessionPayload } from './session-types.js';
 import type {
   StateSyncFullActionPayload,
   StateSyncIncrementalActionPayload,
   UpdateConnectionStatusPayload,
   SetLateResponsePayload,
   UpdateDisconnectedBarPayload,
 } from './socket-types.js';
 import type { SubscriptionUpdateResult } from './subscription-types.js';
 import type { GlobalThemeInfo } from './theme-types.js';
 import type { ThreadActivityStore } from './thread-activity-types.js';
 import type {
   ThreadStore,
   ChangeThreadSettingsPayload,
   LeaveThreadPayload,
   NewThreadResult,
   ThreadJoinPayload,
   ToggleMessagePinResult,
   RoleModificationPayload,
   RoleDeletionPayload,
 } from './thread-types.js';
 import type { ClientUpdatesResultWithUserInfos } from './update-types.js';
 import type { CurrentUserInfo, UserInfos, UserStore } from './user-types.js';
 import type { SetDeviceTokenActionPayload } from '../actions/device-actions.js';
 import type { Shape } from '../types/core.js';
 import type { NotifPermissionAlertInfo } from '../utils/push-alerts.js';
 
 export type BaseAppState<NavInfo: BaseNavInfo = BaseNavInfo> = {
   +navInfo: NavInfo,
   +currentUserInfo: ?CurrentUserInfo,
   +draftStore: DraftStore,
   +entryStore: EntryStore,
   +threadStore: ThreadStore,
   +userStore: UserStore,
   +messageStore: MessageStore,
   +loadingStatuses: { [key: string]: { [idx: number]: LoadingStatus } },
   +calendarFilters: $ReadOnlyArray<CalendarFilter>,
   +notifPermissionAlertInfo: NotifPermissionAlertInfo,
   +actualizedCalendarQuery: CalendarQuery,
   +watchedThreadIDs: $ReadOnlyArray<string>,
   +lifecycleState: LifecycleState,
   +enabledApps: EnabledApps,
   +reportStore: ReportStore,
   +nextLocalID: number,
   +dataLoaded: boolean,
   +userPolicies: UserPolicies,
   +commServicesAccessToken: ?string,
   +inviteLinksStore: InviteLinksStore,
   +keyserverStore: KeyserverStore,
   +threadActivityStore: ThreadActivityStore,
   +integrityStore: IntegrityStore,
   +globalThemeInfo: GlobalThemeInfo,
   ...
 };
 
 export type NativeAppState = BaseAppState<>;
 export type WebAppState = BaseAppState<> & {
-  +cryptoStore: CryptoStore,
+  +cryptoStore: ?CryptoStore,
   +pushApiPublicKey: ?string,
   ...
 };
 export type AppState = NativeAppState | WebAppState;
 
 export type BaseAction =
   | {
       +type: '@@redux/INIT',
       +payload?: void,
     }
   | {
       +type: 'FETCH_ENTRIES_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_ENTRIES_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_ENTRIES_SUCCESS',
       +payload: FetchEntryInfosResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'LOG_OUT_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'LOG_OUT_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'LOG_OUT_SUCCESS',
       +payload: LogOutResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CLAIM_USERNAME_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CLAIM_USERNAME_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CLAIM_USERNAME_SUCCESS',
       +payload: ClaimUsernameResponse,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'DELETE_ACCOUNT_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'DELETE_ACCOUNT_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'DELETE_ACCOUNT_SUCCESS',
       +payload: LogOutResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CREATE_LOCAL_ENTRY',
       +payload: RawEntryInfo,
     }
   | {
       +type: 'CREATE_ENTRY_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CREATE_ENTRY_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CREATE_ENTRY_SUCCESS',
       +payload: CreateEntryPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SAVE_ENTRY_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SAVE_ENTRY_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SAVE_ENTRY_SUCCESS',
       +payload: SaveEntryPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CONCURRENT_MODIFICATION_RESET',
       +payload: {
         +id: string,
         +dbText: string,
       },
     }
   | {
       +type: 'DELETE_ENTRY_STARTED',
       +loadingInfo: LoadingInfo,
       +payload: {
         +localID: ?string,
         +serverID: ?string,
       },
     }
   | {
       +type: 'DELETE_ENTRY_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'DELETE_ENTRY_SUCCESS',
       +payload: ?DeleteEntryResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'LOG_IN_STARTED',
       +loadingInfo: LoadingInfo,
       +payload: LogInStartingPayload,
     }
   | {
       +type: 'LOG_IN_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'LOG_IN_SUCCESS',
       +payload: LogInResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'REGISTER_STARTED',
       +loadingInfo: LoadingInfo,
       +payload: LogInStartingPayload,
     }
   | {
       +type: 'REGISTER_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'REGISTER_SUCCESS',
       +payload: RegisterResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CHANGE_USER_PASSWORD_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CHANGE_USER_PASSWORD_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CHANGE_USER_PASSWORD_SUCCESS',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CHANGE_THREAD_SETTINGS_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CHANGE_THREAD_SETTINGS_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CHANGE_THREAD_SETTINGS_SUCCESS',
       +payload: ChangeThreadSettingsPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'DELETE_THREAD_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'DELETE_THREAD_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'DELETE_THREAD_SUCCESS',
       +payload: LeaveThreadPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'NEW_THREAD_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'NEW_THREAD_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'NEW_THREAD_SUCCESS',
       +payload: NewThreadResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'REMOVE_USERS_FROM_THREAD_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'REMOVE_USERS_FROM_THREAD_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'REMOVE_USERS_FROM_THREAD_SUCCESS',
       +payload: ChangeThreadSettingsPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CHANGE_THREAD_MEMBER_ROLES_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CHANGE_THREAD_MEMBER_ROLES_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CHANGE_THREAD_MEMBER_ROLES_SUCCESS',
       +payload: ChangeThreadSettingsPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_REVISIONS_FOR_ENTRY_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_REVISIONS_FOR_ENTRY_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_REVISIONS_FOR_ENTRY_SUCCESS',
       +payload: {
         +entryID: string,
         +text: string,
         +deleted: boolean,
       },
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'RESTORE_ENTRY_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'RESTORE_ENTRY_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'RESTORE_ENTRY_SUCCESS',
       +payload: RestoreEntryPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'JOIN_THREAD_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'JOIN_THREAD_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'JOIN_THREAD_SUCCESS',
       +payload: ThreadJoinPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'LEAVE_THREAD_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'LEAVE_THREAD_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'LEAVE_THREAD_SUCCESS',
       +payload: LeaveThreadPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SET_NEW_SESSION',
       +payload: SetSessionPayload,
     }
   | {
       +type: 'persist/REHYDRATE',
       +payload: ?BaseAppState<>,
     }
   | {
       +type: 'FETCH_MESSAGES_BEFORE_CURSOR_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_MESSAGES_BEFORE_CURSOR_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_MESSAGES_BEFORE_CURSOR_SUCCESS',
       +payload: FetchMessageInfosPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_MOST_RECENT_MESSAGES_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_MOST_RECENT_MESSAGES_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_MOST_RECENT_MESSAGES_SUCCESS',
       +payload: FetchMessageInfosPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_SINGLE_MOST_RECENT_MESSAGES_FROM_THREADS_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_SINGLE_MOST_RECENT_MESSAGES_FROM_THREADS_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_SINGLE_MOST_RECENT_MESSAGES_FROM_THREADS_SUCCESS',
       +payload: SimpleMessagesPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_TEXT_MESSAGE_STARTED',
       +loadingInfo?: LoadingInfo,
       +payload: RawTextMessageInfo,
     }
   | {
       +type: 'SEND_TEXT_MESSAGE_FAILED',
       +error: true,
       +payload: Error & {
         +localID: string,
         +threadID: string,
       },
       +loadingInfo?: LoadingInfo,
     }
   | {
       +type: 'SEND_TEXT_MESSAGE_SUCCESS',
       +payload: SendMessagePayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_MULTIMEDIA_MESSAGE_STARTED',
       +loadingInfo?: LoadingInfo,
       +payload: RawMultimediaMessageInfo,
     }
   | {
       +type: 'SEND_MULTIMEDIA_MESSAGE_FAILED',
       +error: true,
       +payload: Error & {
         +localID: string,
         +threadID: string,
       },
       +loadingInfo?: LoadingInfo,
     }
   | {
       +type: 'SEND_MULTIMEDIA_MESSAGE_SUCCESS',
       +payload: SendMessagePayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_REACTION_MESSAGE_STARTED',
       +loadingInfo?: LoadingInfo,
       +payload: RawReactionMessageInfo,
     }
   | {
       +type: 'SEND_REACTION_MESSAGE_FAILED',
       +error: true,
       +payload: Error & {
         +localID: string,
         +threadID: string,
         +targetMessageID: string,
         +reaction: string,
         +action: string,
       },
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_REACTION_MESSAGE_SUCCESS',
       +payload: SendMessagePayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEARCH_USERS_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEARCH_USERS_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEARCH_USERS_SUCCESS',
       +payload: UserSearchResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'EXACT_SEARCH_USER_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'EXACT_SEARCH_USER_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'EXACT_SEARCH_USER_SUCCESS',
       +payload: ExactUserSearchResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'UPDATE_DRAFT',
       +payload: {
         +key: string,
         +text: string,
       },
     }
   | {
       +type: 'MOVE_DRAFT',
       +payload: {
         +oldKey: string,
         +newKey: string,
       },
     }
   | {
       +type: 'SET_CLIENT_DB_STORE',
       +payload: {
         +currentUserID: ?string,
         +drafts: $ReadOnlyArray<ClientDBDraftInfo>,
         +messages: ?$ReadOnlyArray<ClientDBMessageInfo>,
         +threadStore: ?ThreadStore,
         +messageStoreThreads: ?$ReadOnlyArray<ClientDBThreadMessageInfo>,
         +reports: ?$ReadOnlyArray<ClientReportCreationRequest>,
         +users: ?UserInfos,
       },
     }
   | {
       +type: 'UPDATE_ACTIVITY_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'UPDATE_ACTIVITY_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'UPDATE_ACTIVITY_SUCCESS',
       +payload: ActivityUpdateSuccessPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SET_DEVICE_TOKEN_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SET_DEVICE_TOKEN_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SET_DEVICE_TOKEN_SUCCESS',
       +payload: SetDeviceTokenActionPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_REPORT_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_REPORT_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_REPORT_SUCCESS',
       +payload?: ClearDeliveredReportsPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_REPORTS_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_REPORTS_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_REPORTS_SUCCESS',
       +payload?: ClearDeliveredReportsPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'QUEUE_REPORTS',
       +payload: QueueReportsPayload,
     }
   | {
       +type: 'SET_URL_PREFIX',
       +payload: string,
     }
   | {
       +type: 'SAVE_MESSAGES',
       +payload: SaveMessagesPayload,
     }
   | {
       +type: 'UPDATE_CALENDAR_THREAD_FILTER',
       +payload: CalendarThreadFilter,
     }
   | {
       +type: 'CLEAR_CALENDAR_THREAD_FILTER',
       +payload?: void,
     }
   | {
       +type: 'SET_CALENDAR_DELETED_FILTER',
       +payload: SetCalendarDeletedFilterPayload,
     }
   | {
       +type: 'UPDATE_SUBSCRIPTION_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'UPDATE_SUBSCRIPTION_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'UPDATE_SUBSCRIPTION_SUCCESS',
       +payload: SubscriptionUpdateResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'UPDATE_CALENDAR_QUERY_STARTED',
       +loadingInfo: LoadingInfo,
       +payload?: CalendarQueryUpdateStartingPayload,
     }
   | {
       +type: 'UPDATE_CALENDAR_QUERY_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'UPDATE_CALENDAR_QUERY_SUCCESS',
       +payload: CalendarQueryUpdateResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FULL_STATE_SYNC',
       +payload: StateSyncFullActionPayload,
     }
   | {
       +type: 'INCREMENTAL_STATE_SYNC',
       +payload: StateSyncIncrementalActionPayload,
     }
   | ProcessServerRequestAction
   | {
       +type: 'UPDATE_CONNECTION_STATUS',
       +payload: UpdateConnectionStatusPayload,
     }
   | {
       +type: 'QUEUE_ACTIVITY_UPDATES',
       +payload: QueueActivityUpdatesPayload,
     }
   | {
       +type: 'UNSUPERVISED_BACKGROUND',
       +payload: { +keyserverID: string },
     }
   | {
       +type: 'UPDATE_LIFECYCLE_STATE',
       +payload: LifecycleState,
     }
   | {
       +type: 'ENABLE_APP',
       +payload: SupportedApps,
     }
   | {
       +type: 'DISABLE_APP',
       +payload: SupportedApps,
     }
   | {
       +type: 'UPDATE_REPORTS_ENABLED',
       +payload: Shape<EnabledReports>,
     }
   | {
       +type: 'PROCESS_UPDATES',
       +payload: ClientUpdatesResultWithUserInfos,
     }
   | {
       +type: 'PROCESS_MESSAGES',
       +payload: NewMessagesPayload,
     }
   | {
       +type: 'MESSAGE_STORE_PRUNE',
       +payload: MessageStorePrunePayload,
     }
   | {
       +type: 'SET_LATE_RESPONSE',
       +payload: SetLateResponsePayload,
     }
   | {
       +type: 'UPDATE_DISCONNECTED_BAR',
       +payload: UpdateDisconnectedBarPayload,
     }
   | {
       +type: 'REQUEST_ACCESS_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'REQUEST_ACCESS_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'REQUEST_ACCESS_SUCCESS',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'UPDATE_MULTIMEDIA_MESSAGE_MEDIA',
       +payload: UpdateMultimediaMessageMediaPayload,
     }
   | {
       +type: 'CREATE_LOCAL_MESSAGE',
       +payload: LocallyComposedMessageInfo,
     }
   | {
       +type: 'UPDATE_RELATIONSHIPS_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'UPDATE_RELATIONSHIPS_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'UPDATE_RELATIONSHIPS_SUCCESS',
       +payload: RelationshipErrors,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SET_THREAD_UNREAD_STATUS_STARTED',
       +payload: {
         +threadID: string,
         +unread: boolean,
       },
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SET_THREAD_UNREAD_STATUS_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SET_THREAD_UNREAD_STATUS_SUCCESS',
       +payload: SetThreadUnreadStatusPayload,
     }
   | {
       +type: 'SET_USER_SETTINGS_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SET_USER_SETTINGS_SUCCESS',
       +payload: DefaultNotificationPayload,
     }
   | {
       +type: 'SET_USER_SETTINGS_FAILED',
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_MESSAGE_REPORT_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_MESSAGE_REPORT_SUCCESS',
       +payload: MessageReportCreationResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_MESSAGE_REPORT_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FORCE_POLICY_ACKNOWLEDGMENT',
       +payload: ForcePolicyAcknowledgmentPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'POLICY_ACKNOWLEDGMENT_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'POLICY_ACKNOWLEDGMENT_SUCCESS',
       +payload: PolicyAcknowledgmentPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'POLICY_ACKNOWLEDGMENT_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'GET_SIWE_NONCE_STARTED',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'GET_SIWE_NONCE_SUCCESS',
       +payload?: void,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'GET_SIWE_NONCE_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SIWE_AUTH_STARTED',
       +payload: LogInStartingPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SIWE_AUTH_SUCCESS',
       +payload: LogInResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SIWE_AUTH_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'RECORD_NOTIF_PERMISSION_ALERT',
       +payload: { +time: number },
     }
   | {
       +type: 'UPDATE_USER_AVATAR_STARTED',
       +payload: UpdateUserAvatarRequest,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'UPDATE_USER_AVATAR_SUCCESS',
       +payload: UpdateUserAvatarResponse,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'UPDATE_USER_AVATAR_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_EDIT_MESSAGE_STARTED',
       +loadingInfo?: LoadingInfo,
       +payload?: void,
     }
   | {
       +type: 'SEND_EDIT_MESSAGE_SUCCESS',
       +payload: EditMessagePayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEND_EDIT_MESSAGE_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'TOGGLE_MESSAGE_PIN_STARTED',
       +loadingInfo?: LoadingInfo,
       +payload?: void,
     }
   | {
       +type: 'TOGGLE_MESSAGE_PIN_SUCCESS',
       +payload: ToggleMessagePinResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'TOGGLE_MESSAGE_PIN_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_PINNED_MESSAGES_STARTED',
       +loadingInfo?: LoadingInfo,
       +payload?: void,
     }
   | {
       +type: 'FETCH_PINNED_MESSAGES_SUCCESS',
       +payload: FetchPinnedMessagesResult,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_PINNED_MESSAGES_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'VERIFY_INVITE_LINK_STARTED',
       +loadingInfo?: LoadingInfo,
       +payload?: void,
     }
   | {
       +type: 'VERIFY_INVITE_LINK_SUCCESS',
       +payload: InviteLinkVerificationResponse,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'VERIFY_INVITE_LINK_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_PRIMARY_INVITE_LINKS_STARTED',
       +loadingInfo?: LoadingInfo,
       +payload?: void,
     }
   | {
       +type: 'FETCH_PRIMARY_INVITE_LINKS_SUCCESS',
       +payload: FetchInviteLinksResponse,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'FETCH_PRIMARY_INVITE_LINKS_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'UPDATE_CALENDAR_COMMUNITY_FILTER',
       +payload: string,
     }
   | {
       +type: 'CLEAR_CALENDAR_COMMUNITY_FILTER',
       +payload: void,
     }
   | {
       +type: 'UPDATE_CHAT_COMMUNITY_FILTER',
       +payload: string,
     }
   | {
       +type: 'CLEAR_CHAT_COMMUNITY_FILTER',
       +payload: void,
     }
   | {
       +type: 'SEARCH_MESSAGES_STARTED',
       +payload: void,
       +loadingInfo?: LoadingInfo,
     }
   | {
       +type: 'SEARCH_MESSAGES_SUCCESS',
       +payload: SearchMessagesResponse,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SEARCH_MESSAGES_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CREATE_OR_UPDATE_PUBLIC_LINK_STARTED',
       +loadingInfo?: LoadingInfo,
       +payload?: void,
     }
   | {
       +type: 'CREATE_OR_UPDATE_PUBLIC_LINK_SUCCESS',
       +payload: InviteLink,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'CREATE_OR_UPDATE_PUBLIC_LINK_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'DISABLE_INVITE_LINK_STARTED',
       +loadingInfo?: LoadingInfo,
       +payload?: void,
     }
   | {
       +type: 'DISABLE_INVITE_LINK_SUCCESS',
       +payload: DisableInviteLinkPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'DISABLE_INVITE_LINK_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'GET_OLM_SESSION_INITIALIZATION_DATA_STARTED',
       +loadingInfo?: LoadingInfo,
       +payload?: void,
     }
   | {
       +type: 'GET_OLM_SESSION_INITIALIZATION_DATA_SUCCESS',
       +payload: GetOlmSessionInitializationDataResponse,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'GET_OLM_SESSION_INITIALIZATION_DATA_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SET_DATA_LOADED',
       +payload: {
         +dataLoaded: boolean,
       },
     }
   | {
       +type: 'GET_VERSION_STARTED',
       +loadingInfo?: LoadingInfo,
       +payload?: void,
     }
   | {
       +type: 'GET_VERSION_SUCCESS',
       +payload: GetVersionActionPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'GET_VERSION_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'UPDATE_LAST_COMMUNICATED_PLATFORM_DETAILS',
       +payload: LastCommunicatedPlatformDetails,
     }
   | { +type: 'RESET_USER_STATE', +payload?: void }
   | {
       +type: 'MODIFY_COMMUNITY_ROLE_STARTED',
       +loadingInfo?: LoadingInfo,
       +payload?: void,
     }
   | {
       +type: 'MODIFY_COMMUNITY_ROLE_SUCCESS',
       +payload: RoleModificationPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'MODIFY_COMMUNITY_ROLE_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'DELETE_COMMUNITY_ROLE_STARTED',
       +loadingInfo?: LoadingInfo,
       +payload?: void,
     }
   | {
       +type: 'DELETE_COMMUNITY_ROLE_SUCCESS',
       +payload: RoleDeletionPayload,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'DELETE_COMMUNITY_ROLE_FAILED',
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
     }
   | {
       +type: 'SET_ACCESS_TOKEN',
       +payload: string,
     }
   | {
       +type: 'UPDATE_THREAD_LAST_NAVIGATED',
       +payload: { +threadID: string, +time: number },
     }
   | {
       +type: 'UPDATE_INTEGRITY_STORE',
       +payload: {
         +threadIDsToHash?: $ReadOnlyArray<string>,
         +threadHashingStatus?: 'starting' | 'running' | 'completed',
       },
     }
   | {
       +type: 'UPDATE_THEME_INFO',
       +payload: Shape<GlobalThemeInfo>,
     }
   | {
       +type: 'ADD_KEYSERVER',
       +payload: AddKeyserverPayload,
     }
   | {
       +type: 'REMOVE_KEYSERVER',
       +payload: RemoveKeyserverPayload,
     };
 
 export type ActionPayload = ?(Object | Array<*> | $ReadOnlyArray<*> | string);
 export type SuperAction = {
   type: string,
   payload?: ActionPayload,
   loadingInfo?: LoadingInfo,
   error?: boolean,
 };
 type ThunkedAction = (dispatch: Dispatch) => void;
 export type PromisedAction = (dispatch: Dispatch) => Promise<void>;
 export type Dispatch = ((promisedAction: PromisedAction) => Promise<void>) &
   ((thunkedAction: ThunkedAction) => void) &
   ((action: SuperAction) => boolean);
 
 // This is lifted from redux-persist/lib/constants.js
 // I don't want to add redux-persist to the web/server bundles...
 // import { REHYDRATE } from 'redux-persist';
 export const rehydrateActionType = 'persist/REHYDRATE';
diff --git a/web/account/log-in-form.react.js b/web/account/log-in-form.react.js
index 1ac7c9523..84579f1e7 100644
--- a/web/account/log-in-form.react.js
+++ b/web/account/log-in-form.react.js
@@ -1,162 +1,140 @@
 // @flow
 
 import olm from '@commapp/olm';
 import { useConnectModal } from '@rainbow-me/rainbowkit';
 import * as React from 'react';
 import { useDispatch } from 'react-redux';
 import uuid from 'uuid';
 import { useWalletClient } from 'wagmi';
 
 import { isDev } from 'lib/utils/dev-utils.js';
 
 import css from './log-in-form.css';
 import SIWEButton from './siwe-button.react.js';
 import SIWELoginForm from './siwe-login-form.react.js';
 import TraditionalLoginForm from './traditional-login-form.react.js';
 import Button from '../components/button.react.js';
 import OrBreak from '../components/or-break.react.js';
 import { initOlm } from '../olm/olm-utils.js';
 import { updateNavInfoActionType } from '../redux/action-types.js';
-import {
-  setPrimaryIdentityKeys,
-  setNotificationIdentityKeys,
-  setPickledPrimaryAccount,
-  setPickledNotificationAccount,
-} from '../redux/crypto-store-reducer.js';
+import { setCryptoStore } from '../redux/crypto-store-reducer.js';
 import { useSelector } from '../redux/redux-utils.js';
 
 function LoginForm(): React.Node {
   const { openConnectModal } = useConnectModal();
   const { data: signer } = useWalletClient();
   const dispatch = useDispatch();
 
-  const primaryIdentityPublicKeys = useSelector(
-    state => state.cryptoStore.primaryIdentityKeys,
-  );
-  const notificationIdentityPublicKeys = useSelector(
-    state => state.cryptoStore.notificationIdentityKeys,
-  );
+  const cryptoStore = useSelector(state => state.cryptoStore);
 
   React.useEffect(() => {
     (async () => {
-      if (
-        primaryIdentityPublicKeys !== null &&
-        primaryIdentityPublicKeys !== undefined &&
-        notificationIdentityPublicKeys !== null &&
-        notificationIdentityPublicKeys !== undefined
-      ) {
+      if (cryptoStore !== null && cryptoStore !== undefined) {
         return;
       }
       await initOlm();
 
       const identityAccount = new olm.Account();
       identityAccount.create();
       const { ed25519: identityED25519, curve25519: identityCurve25519 } =
         JSON.parse(identityAccount.identity_keys());
 
-      dispatch({
-        type: setPrimaryIdentityKeys,
-        payload: { ed25519: identityED25519, curve25519: identityCurve25519 },
-      });
-
       const identityAccountPicklingKey = uuid.v4();
       const pickledIdentityAccount = identityAccount.pickle(
         identityAccountPicklingKey,
       );
 
-      dispatch({
-        type: setPickledPrimaryAccount,
-        payload: {
-          picklingKey: identityAccountPicklingKey,
-          pickledAccount: pickledIdentityAccount,
-        },
-      });
-
       const notificationAccount = new olm.Account();
       notificationAccount.create();
       const {
         ed25519: notificationED25519,
         curve25519: notificationCurve25519,
       } = JSON.parse(notificationAccount.identity_keys());
 
-      dispatch({
-        type: setNotificationIdentityKeys,
-        payload: {
-          ed25519: notificationED25519,
-          curve25519: notificationCurve25519,
-        },
-      });
-
       const notificationAccountPicklingKey = uuid.v4();
       const pickledNotificationAccount = notificationAccount.pickle(
         notificationAccountPicklingKey,
       );
 
       dispatch({
-        type: setPickledNotificationAccount,
+        type: setCryptoStore,
         payload: {
-          picklingKey: notificationAccountPicklingKey,
-          pickledAccount: pickledNotificationAccount,
+          primaryAccount: {
+            picklingKey: identityAccountPicklingKey,
+            pickledAccount: pickledIdentityAccount,
+          },
+          primaryIdentityKeys: {
+            ed25519: identityED25519,
+            curve25519: identityCurve25519,
+          },
+          notificationAccount: {
+            picklingKey: notificationAccountPicklingKey,
+            pickledAccount: pickledNotificationAccount,
+          },
+          notificationIdentityKeys: {
+            ed25519: notificationED25519,
+            curve25519: notificationCurve25519,
+          },
         },
       });
     })();
-  }, [dispatch, notificationIdentityPublicKeys, primaryIdentityPublicKeys]);
+  }, [dispatch, cryptoStore]);
 
   const onQRCodeLoginButtonClick = React.useCallback(() => {
     dispatch({
       type: updateNavInfoActionType,
       payload: {
         loginMethod: 'qr-code',
       },
     });
   }, [dispatch]);
 
   const qrCodeLoginButton = React.useMemo(() => {
     if (!isDev) {
       return null;
     }
 
     return (
       <div className={css.form_qrcode_login}>
         <Button
           variant="outline"
           type="submit"
           onClick={onQRCodeLoginButtonClick}
         >
           Sign in via QR Code
         </Button>
       </div>
     );
   }, [onQRCodeLoginButtonClick]);
 
   const [siweAuthFlowSelected, setSIWEAuthFlowSelected] =
     React.useState<boolean>(false);
 
   const onSIWEButtonClick = React.useCallback(() => {
     setSIWEAuthFlowSelected(true);
     openConnectModal && openConnectModal();
   }, [openConnectModal]);
 
   const cancelSIWEAuthFlow = React.useCallback(() => {
     setSIWEAuthFlowSelected(false);
   }, []);
 
   if (siweAuthFlowSelected && signer) {
     return (
       <div className={css.modal_body}>
         <SIWELoginForm cancelSIWEAuthFlow={cancelSIWEAuthFlow} />
       </div>
     );
   }
 
   return (
     <div className={css.modal_body}>
       <TraditionalLoginForm />
       <OrBreak />
       <SIWEButton onSIWEButtonClick={onSIWEButtonClick} />
       {qrCodeLoginButton}
     </div>
   );
 }
 
 export default LoginForm;
diff --git a/web/account/qr-code-login.react.js b/web/account/qr-code-login.react.js
index 2ec3ae814..ae9da49b4 100644
--- a/web/account/qr-code-login.react.js
+++ b/web/account/qr-code-login.react.js
@@ -1,62 +1,62 @@
 // @flow
 
 import { QRCodeSVG } from 'qrcode.react';
 import * as React from 'react';
 
 import { qrCodeLinkURL } from 'lib/facts/links.js';
 import { generateKeyCommon } from 'lib/media/aes-crypto-utils-common.js';
 import { uintArrayToHexString } from 'lib/media/data-utils.js';
 
 import css from './qr-code-login.css';
 import { useSelector } from '../redux/redux-utils.js';
 
 function QrCodeLogin(): React.Node {
   const [qrCodeValue, setQrCodeValue] = React.useState<?string>();
   const ed25519Key = useSelector(
-    state => state.cryptoStore.primaryIdentityKeys?.ed25519,
+    state => state.cryptoStore?.primaryIdentityKeys.ed25519,
   );
 
   const generateQRCode = React.useCallback(async () => {
     try {
       if (!ed25519Key) {
         return;
       }
 
       const rawAESKey: Uint8Array = await generateKeyCommon(crypto);
       const aesKeyAsHexString: string = uintArrayToHexString(rawAESKey);
 
       const url = qrCodeLinkURL(aesKeyAsHexString, ed25519Key);
       setQrCodeValue(url);
     } catch (err) {
       console.error('Failed to generate QR Code:', err);
     }
   }, [ed25519Key]);
 
   React.useEffect(() => {
     generateQRCode();
   }, [generateQRCode]);
 
   return (
     <div className={css.qrContainer}>
       <div className={css.title}>Log in to Comm</div>
       <div className={css.scanInstructions}>
         Open the Comm app on your phone and scan the QR code below
       </div>
       <QRCodeSVG value={qrCodeValue} size={300} marginSize={4} level="L" />
       <div className={css.instructionsContainer}>
         <div className={css.instructionsTitle}>How to find the scanner:</div>
         <div className={css.instructionsStep}>
           Go to <strong>Profile</strong>
         </div>
         <div className={css.instructionsStep}>
           Select <strong>Linked devices</strong>
         </div>
         <div className={css.instructionsStep}>
           Click <strong>Add</strong> on the top right
         </div>
       </div>
     </div>
   );
 }
 
 export default QrCodeLogin;
diff --git a/web/account/siwe-login-form.react.js b/web/account/siwe-login-form.react.js
index 58ae4ac16..10a884f38 100644
--- a/web/account/siwe-login-form.react.js
+++ b/web/account/siwe-login-form.react.js
@@ -1,269 +1,269 @@
 // @flow
 
 import '@rainbow-me/rainbowkit/styles.css';
 import classNames from 'classnames';
 import invariant from 'invariant';
 import * as React from 'react';
 import { useDispatch } from 'react-redux';
 import { useAccount, useWalletClient } from 'wagmi';
 
 import { setDataLoadedActionType } from 'lib/actions/client-db-store-actions.js';
 import {
   getSIWENonce,
   getSIWENonceActionTypes,
   siweAuth,
   siweAuthActionTypes,
 } from 'lib/actions/siwe-actions.js';
 import ConnectedWalletInfo from 'lib/components/connected-wallet-info.react.js';
 import SWMansionIcon from 'lib/components/SWMansionIcon.react.js';
 import stores from 'lib/facts/stores.js';
 import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js';
 import type { LogInStartingPayload } from 'lib/types/account-types.js';
 import type {
   OLMIdentityKeys,
   SignedIdentityKeysBlob,
 } from 'lib/types/crypto-types.js';
 import {
   useDispatchActionPromise,
   useServerCall,
 } from 'lib/utils/action-utils.js';
 import { ServerError } from 'lib/utils/errors.js';
 import {
   createSIWEMessage,
   getSIWEStatementForPublicKey,
   siweMessageSigningExplanationStatements,
 } from 'lib/utils/siwe-utils.js';
 
 import { useSignedIdentityKeysBlob } from './account-hooks.js';
 import HeaderSeparator from './header-separator.react.js';
 import css from './siwe.css';
 import Button from '../components/button.react.js';
 import OrBreak from '../components/or-break.react.js';
 import LoadingIndicator from '../loading-indicator.react.js';
 import { useSelector } from '../redux/redux-utils.js';
 import { webLogInExtraInfoSelector } from '../selectors/account-selectors.js';
 
 type SIWELogInError = 'account_does_not_exist';
 
 type SIWELoginFormProps = {
   +cancelSIWEAuthFlow: () => void,
 };
 
 const getSIWENonceLoadingStatusSelector = createLoadingStatusSelector(
   getSIWENonceActionTypes,
 );
 const siweAuthLoadingStatusSelector =
   createLoadingStatusSelector(siweAuthActionTypes);
 function SIWELoginForm(props: SIWELoginFormProps): React.Node {
   const { address } = useAccount();
   const { data: signer } = useWalletClient();
   const dispatchActionPromise = useDispatchActionPromise();
   const getSIWENonceCall = useServerCall(getSIWENonce);
   const getSIWENonceCallLoadingStatus = useSelector(
     getSIWENonceLoadingStatusSelector,
   );
   const siweAuthLoadingStatus = useSelector(siweAuthLoadingStatusSelector);
   const siweAuthCall = useServerCall(siweAuth);
   const logInExtraInfo = useSelector(webLogInExtraInfoSelector);
 
   const [siweNonce, setSIWENonce] = React.useState<?string>(null);
 
   const siweNonceShouldBeFetched =
     !siweNonce && getSIWENonceCallLoadingStatus !== 'loading';
 
   React.useEffect(() => {
     if (!siweNonceShouldBeFetched) {
       return;
     }
     dispatchActionPromise(
       getSIWENonceActionTypes,
       (async () => {
         const response = await getSIWENonceCall();
         setSIWENonce(response);
       })(),
     );
   }, [dispatchActionPromise, getSIWENonceCall, siweNonceShouldBeFetched]);
 
   const primaryIdentityPublicKeys: ?OLMIdentityKeys = useSelector(
-    state => state.cryptoStore.primaryIdentityKeys,
+    state => state.cryptoStore?.primaryIdentityKeys,
   );
 
   const signedIdentityKeysBlob: ?SignedIdentityKeysBlob =
     useSignedIdentityKeysBlob();
 
   const callSIWEAuthEndpoint = React.useCallback(
     async (message: string, signature: string, extraInfo) => {
       invariant(
         signedIdentityKeysBlob,
         'signedIdentityKeysBlob must be set in attemptSIWEAuth',
       );
       try {
         return await siweAuthCall({
           message,
           signature,
           signedIdentityKeysBlob,
           doNotRegister: true,
           ...extraInfo,
         });
       } catch (e) {
         if (
           e instanceof ServerError &&
           e.message === 'account_does_not_exist'
         ) {
           setError('account_does_not_exist');
         }
         throw e;
       }
     },
     [signedIdentityKeysBlob, siweAuthCall],
   );
 
   const attemptSIWEAuth = React.useCallback(
     (message: string, signature: string) => {
       const extraInfo = logInExtraInfo();
       return dispatchActionPromise(
         siweAuthActionTypes,
         callSIWEAuthEndpoint(message, signature, extraInfo),
         undefined,
         ({ calendarQuery: extraInfo.calendarQuery }: LogInStartingPayload),
       );
     },
     [callSIWEAuthEndpoint, dispatchActionPromise, logInExtraInfo],
   );
 
   const dispatch = useDispatch();
   const onSignInButtonClick = React.useCallback(async () => {
     invariant(signer, 'signer must be present during SIWE attempt');
     invariant(siweNonce, 'nonce must be present during SIWE attempt');
     invariant(
       primaryIdentityPublicKeys,
       'primaryIdentityPublicKeys must be present during SIWE attempt',
     );
     const statement = getSIWEStatementForPublicKey(
       primaryIdentityPublicKeys.ed25519,
     );
     const message = createSIWEMessage(address, statement, siweNonce);
     const signature = await signer.signMessage({ message });
     await attemptSIWEAuth(message, signature);
     dispatch({
       type: setDataLoadedActionType,
       payload: {
         dataLoaded: true,
       },
     });
   }, [
     address,
     attemptSIWEAuth,
     primaryIdentityPublicKeys,
     signer,
     siweNonce,
     dispatch,
   ]);
 
   const { cancelSIWEAuthFlow } = props;
 
   const backButtonColor = React.useMemo(
     () => ({ backgroundColor: '#211E2D' }),
     [],
   );
 
   const signInButtonColor = React.useMemo(
     () => ({ backgroundColor: '#6A20E3' }),
     [],
   );
 
   const [error, setError] = React.useState<?SIWELogInError>();
 
   const mainMiddleAreaClassName = classNames({
     [css.mainMiddleArea]: true,
     [css.hidden]: !!error,
   });
   const errorOverlayClassNames = classNames({
     [css.errorOverlay]: true,
     [css.hidden]: !error,
   });
 
   if (
     siweAuthLoadingStatus === 'loading' ||
     !siweNonce ||
     !primaryIdentityPublicKeys ||
     !signedIdentityKeysBlob
   ) {
     return (
       <div className={css.loadingIndicator}>
         <LoadingIndicator status="loading" size="large" />
       </div>
     );
   }
 
   let errorText;
   if (error === 'account_does_not_exist') {
     errorText = (
       <>
         <p className={css.redText}>
           No Comm account found for that Ethereum wallet!
         </p>
         <p>
           We require that users register on their mobile devices. Comm relies on
           a primary device capable of scanning QR codes in order to authorize
           secondary devices.
         </p>
         <p>
           You can install our iOS app&nbsp;
           <a href={stores.appStoreUrl} target="_blank" rel="noreferrer">
             here
           </a>
           , or our Android app&nbsp;
           <a href={stores.googlePlayUrl} target="_blank" rel="noreferrer">
             here
           </a>
           .
         </p>
       </>
     );
   }
 
   return (
     <div className={css.siweLoginFormContainer}>
       <h4>Sign in with Ethereum</h4>
       <HeaderSeparator />
       <div className={css.walletConnectedText}>
         <p>Wallet Connected</p>
       </div>
       <div className={css.connectButtonContainer}>
         <ConnectedWalletInfo />
       </div>
       <div className={css.middleArea}>
         <div className={mainMiddleAreaClassName}>
           <div className={css.messageSigningStatements}>
             <p>{siweMessageSigningExplanationStatements}</p>
             <p>
               By signing up, you agree to our{' '}
               <a href="https://comm.app/terms">Terms of Use</a> &{' '}
               <a href="https://comm.app/privacy">Privacy Policy</a>.
             </p>
           </div>
           <Button
             variant="filled"
             onClick={onSignInButtonClick}
             buttonColor={signInButtonColor}
           >
             Sign in using this wallet
           </Button>
         </div>
         <div className={errorOverlayClassNames}>{errorText}</div>
       </div>
       <OrBreak />
       <Button
         variant="filled"
         onClick={cancelSIWEAuthFlow}
         buttonColor={backButtonColor}
       >
         <SWMansionIcon icon="chevron-left" size={18} />
         Back to sign in with username
       </Button>
     </div>
   );
 }
 
 export default SIWELoginForm;
diff --git a/web/redux/crypto-store-reducer.js b/web/redux/crypto-store-reducer.js
index 8bd53dd40..cafc9f905 100644
--- a/web/redux/crypto-store-reducer.js
+++ b/web/redux/crypto-store-reducer.js
@@ -1,60 +1,28 @@
 // @flow
 
 import {
   logOutActionTypes,
   deleteAccountActionTypes,
 } from 'lib/actions/user-actions.js';
 import type { CryptoStore } from 'lib/types/crypto-types.js';
 import { setNewSessionActionType } from 'lib/utils/action-utils.js';
 
 import type { Action } from './redux-setup.js';
 
-const setPrimaryIdentityKeys = 'SET_PRIMARY_IDENTITY_KEYS';
-const setNotificationIdentityKeys = 'SET_NOTIFICATION_IDENTITY_KEYS';
-const setPickledPrimaryAccount = 'SET_PICKLED_PRIMARY_ACCOUNT';
-const setPickledNotificationAccount = 'SET_PICKLED_NOTIFICATION_ACCOUNT';
+const setCryptoStore = 'SET_CRYPTO_STORE';
 
-function reduceCryptoStore(state: CryptoStore, action: Action): CryptoStore {
-  if (action.type === setPrimaryIdentityKeys) {
-    return {
-      ...state,
-      primaryIdentityKeys: action.payload,
-    };
-  } else if (action.type === setNotificationIdentityKeys) {
-    return {
-      ...state,
-      notificationIdentityKeys: action.payload,
-    };
-  } else if (action.type === setPickledPrimaryAccount) {
-    return {
-      ...state,
-      primaryAccount: action.payload,
-    };
-  } else if (action.type === setPickledNotificationAccount) {
-    return {
-      ...state,
-      notificationAccount: action.payload,
-    };
+function reduceCryptoStore(state: ?CryptoStore, action: Action): ?CryptoStore {
+  if (action.type === setCryptoStore) {
+    return action.payload;
   } else if (
     action.type === logOutActionTypes.success ||
     action.type === deleteAccountActionTypes.success ||
     (action.type === setNewSessionActionType &&
       action.payload.sessionChange.cookieInvalidated)
   ) {
-    return {
-      primaryAccount: null,
-      primaryIdentityKeys: null,
-      notificationAccount: null,
-      notificationIdentityKeys: null,
-    };
+    return null;
   }
   return state;
 }
 
-export {
-  setPrimaryIdentityKeys,
-  setNotificationIdentityKeys,
-  setPickledPrimaryAccount,
-  setPickledNotificationAccount,
-  reduceCryptoStore,
-};
+export { setCryptoStore, reduceCryptoStore };
diff --git a/web/redux/default-state.js b/web/redux/default-state.js
index 4a7cd6944..3ce8a25f0 100644
--- a/web/redux/default-state.js
+++ b/web/redux/default-state.js
@@ -1,95 +1,90 @@
 // @flow
 
 import { defaultEnabledApps } from 'lib/types/enabled-apps.js';
 import { defaultCalendarFilters } from 'lib/types/filter-types.js';
 import { defaultConnectionInfo } from 'lib/types/socket-types.js';
 import { defaultGlobalThemeInfo } from 'lib/types/theme-types.js';
 import { defaultNotifPermissionAlertInfo } from 'lib/utils/push-alerts.js';
 import { ashoatKeyserverID } from 'lib/utils/validation-utils.js';
 
 import type { AppState } from './redux-setup.js';
 
 declare var keyserverURL: string;
 
 const defaultWebState: AppState = Object.freeze({
   navInfo: {
     activeChatThreadID: null,
     startDate: '',
     endDate: '',
     tab: 'chat',
   },
   currentUserInfo: null,
   draftStore: { drafts: {} },
   entryStore: {
     entryInfos: {},
     daysToEntries: {},
     lastUserInteractionCalendar: 0,
   },
   threadStore: {
     threadInfos: {},
   },
   userStore: {
     userInfos: {},
   },
   messageStore: {
     messages: {},
     threads: {},
     local: {},
     currentAsOf: { [ashoatKeyserverID]: 0 },
   },
   windowActive: true,
   pushApiPublicKey: null,
-  cryptoStore: {
-    primaryAccount: null,
-    primaryIdentityKeys: null,
-    notificationAccount: null,
-    notificationIdentityKeys: null,
-  },
+  cryptoStore: null,
   windowDimensions: { width: window.width, height: window.height },
   loadingStatuses: {},
   calendarFilters: defaultCalendarFilters,
   dataLoaded: false,
   notifPermissionAlertInfo: defaultNotifPermissionAlertInfo,
   watchedThreadIDs: [],
   lifecycleState: 'active',
   enabledApps: defaultEnabledApps,
   reportStore: {
     enabledReports: {
       crashReports: false,
       inconsistencyReports: false,
       mediaReports: false,
     },
     queuedReports: [],
   },
   nextLocalID: 0,
   _persist: null,
   userPolicies: {},
   commServicesAccessToken: null,
   inviteLinksStore: {
     links: {},
   },
   actualizedCalendarQuery: {
     startDate: '',
     endDate: '',
     filters: defaultCalendarFilters,
   },
   communityPickerStore: { chat: null, calendar: null },
   keyserverStore: {
     keyserverInfos: {
       [ashoatKeyserverID]: {
         cookie: null,
         updatesCurrentAsOf: 0,
         urlPrefix: keyserverURL,
         connection: { ...defaultConnectionInfo },
         lastCommunicatedPlatformDetails: null,
         deviceToken: null,
       },
     },
   },
   threadActivityStore: {},
   initialStateLoaded: false,
   integrityStore: { threadHashes: {}, threadHashingStatus: 'starting' },
   globalThemeInfo: defaultGlobalThemeInfo,
 });
 
 export { defaultWebState };
diff --git a/web/redux/redux-setup.js b/web/redux/redux-setup.js
index 97174c04c..efd470f12 100644
--- a/web/redux/redux-setup.js
+++ b/web/redux/redux-setup.js
@@ -1,341 +1,325 @@
 // @flow
 
 import invariant from 'invariant';
 import type { PersistState } from 'redux-persist/es/types.js';
 
 import {
   logOutActionTypes,
   deleteAccountActionTypes,
 } from 'lib/actions/user-actions.js';
 import { reportStoreOpsHandlers } from 'lib/ops/report-store-ops.js';
 import baseReducer from 'lib/reducers/master-reducer.js';
 import { mostRecentlyReadThreadSelector } from 'lib/selectors/thread-selectors.js';
 import { isLoggedIn } from 'lib/selectors/user-selectors.js';
 import { invalidSessionDowngrade } from 'lib/shared/session-utils.js';
 import type { Shape } from 'lib/types/core.js';
-import type {
-  CryptoStore,
-  OLMIdentityKeys,
-  PickledOLMAccount,
-} from 'lib/types/crypto-types.js';
+import type { CryptoStore } from 'lib/types/crypto-types.js';
 import type { DraftStore } from 'lib/types/draft-types.js';
 import type { EnabledApps } from 'lib/types/enabled-apps.js';
 import type { EntryStore, CalendarQuery } from 'lib/types/entry-types.js';
 import { type CalendarFilter } from 'lib/types/filter-types.js';
 import type { IntegrityStore } from 'lib/types/integrity-types.js';
 import type { KeyserverStore } from 'lib/types/keyserver-types.js';
 import type { LifecycleState } from 'lib/types/lifecycle-state-types.js';
 import type { InviteLinksStore } from 'lib/types/link-types.js';
 import type { LoadingStatus } from 'lib/types/loading-types.js';
 import type { MessageStore } from 'lib/types/message-types.js';
 import type { UserPolicies } from 'lib/types/policy-types.js';
 import type { BaseAction } from 'lib/types/redux-types.js';
 import type { ReportStore } from 'lib/types/report-types.js';
 import type { GlobalThemeInfo } from 'lib/types/theme-types.js';
 import type { ThreadActivityStore } from 'lib/types/thread-activity-types';
 import type { ThreadStore } from 'lib/types/thread-types.js';
 import type { CurrentUserInfo, UserStore } from 'lib/types/user-types.js';
 import { setNewSessionActionType } from 'lib/utils/action-utils.js';
 import type { NotifPermissionAlertInfo } from 'lib/utils/push-alerts.js';
 import { ashoatKeyserverID } from 'lib/utils/validation-utils.js';
 
 import {
   updateWindowActiveActionType,
   updateNavInfoActionType,
   updateWindowDimensionsActionType,
   setInitialReduxState,
 } from './action-types.js';
 import { reduceCommunityPickerStore } from './community-picker-reducer.js';
-import {
-  reduceCryptoStore,
-  setPrimaryIdentityKeys,
-  setNotificationIdentityKeys,
-  setPickledNotificationAccount,
-  setPickledPrimaryAccount,
-} from './crypto-store-reducer.js';
+import { reduceCryptoStore, setCryptoStore } from './crypto-store-reducer.js';
 import reduceNavInfo from './nav-reducer.js';
 import { onStateDifference } from './redux-debug-utils.js';
 import { getVisibility } from './visibility.js';
 import { getDatabaseModule } from '../database/database-module-provider.js';
 import { activeThreadSelector } from '../selectors/nav-selectors.js';
 import { type NavInfo } from '../types/nav-types.js';
 import type { InitialReduxState } from '../types/redux-types.js';
 import { workerRequestMessageTypes } from '../types/worker-types.js';
 
 export type WindowDimensions = { width: number, height: number };
 
 export type CommunityPickerStore = {
   +chat: ?string,
   +calendar: ?string,
 };
 
 export type AppState = {
   +navInfo: NavInfo,
   +currentUserInfo: ?CurrentUserInfo,
   +draftStore: DraftStore,
   +entryStore: EntryStore,
   +threadStore: ThreadStore,
   +userStore: UserStore,
   +messageStore: MessageStore,
   +loadingStatuses: { [key: string]: { [idx: number]: LoadingStatus } },
   +calendarFilters: $ReadOnlyArray<CalendarFilter>,
   +communityPickerStore: CommunityPickerStore,
   +windowDimensions: WindowDimensions,
   +notifPermissionAlertInfo: NotifPermissionAlertInfo,
   +actualizedCalendarQuery: CalendarQuery,
   +watchedThreadIDs: $ReadOnlyArray<string>,
   +lifecycleState: LifecycleState,
   +enabledApps: EnabledApps,
   +reportStore: ReportStore,
   +nextLocalID: number,
   +dataLoaded: boolean,
   +windowActive: boolean,
   +userPolicies: UserPolicies,
-  +cryptoStore: CryptoStore,
+  +cryptoStore: ?CryptoStore,
   +pushApiPublicKey: ?string,
   +_persist: ?PersistState,
   +commServicesAccessToken: ?string,
   +inviteLinksStore: InviteLinksStore,
   +keyserverStore: KeyserverStore,
   +threadActivityStore: ThreadActivityStore,
   +initialStateLoaded: boolean,
   +integrityStore: IntegrityStore,
   +globalThemeInfo: GlobalThemeInfo,
 };
 
 export type Action =
   | BaseAction
   | { type: 'UPDATE_NAV_INFO', payload: Shape<NavInfo> }
   | {
       type: 'UPDATE_WINDOW_DIMENSIONS',
       payload: WindowDimensions,
     }
   | {
       type: 'UPDATE_WINDOW_ACTIVE',
       payload: boolean,
     }
-  | { +type: 'SET_PRIMARY_IDENTITY_KEYS', payload: ?OLMIdentityKeys }
-  | { +type: 'SET_NOTIFICATION_IDENTITY_KEYS', payload: ?OLMIdentityKeys }
-  | { +type: 'SET_PICKLED_PRIMARY_ACCOUNT', payload: ?PickledOLMAccount }
-  | { +type: 'SET_PICKLED_NOTIFICATION_ACCOUNT', payload: ?PickledOLMAccount }
+  | { +type: 'SET_CRYPTO_STORE', payload: CryptoStore }
   | { +type: 'SET_INITIAL_REDUX_STATE', payload: InitialReduxState };
 
 export function reducer(oldState: AppState | void, action: Action): AppState {
   invariant(oldState, 'should be set');
   let state = oldState;
 
   if (action.type === setInitialReduxState) {
     const { userInfos, keyserverInfos, ...rest } = action.payload;
     const newKeyserverInfos = { ...state.keyserverStore.keyserverInfos };
     for (const keyserverID in keyserverInfos) {
       newKeyserverInfos[keyserverID] = {
         ...newKeyserverInfos[keyserverID],
         ...keyserverInfos[keyserverID],
       };
     }
     return validateState(oldState, {
       ...state,
       ...rest,
       userStore: { userInfos },
       keyserverStore: {
         ...state.keyserverStore,
         keyserverInfos: newKeyserverInfos,
       },
       initialStateLoaded: true,
     });
   } else if (action.type === updateWindowDimensionsActionType) {
     return validateState(oldState, {
       ...state,
       windowDimensions: action.payload,
     });
   } else if (action.type === updateWindowActiveActionType) {
     return validateState(oldState, {
       ...state,
       windowActive: action.payload,
     });
   } else if (action.type === setNewSessionActionType) {
     if (
       invalidSessionDowngrade(
         oldState,
         action.payload.sessionChange.currentUserInfo,
         action.payload.preRequestUserState,
       )
     ) {
       return oldState;
     }
 
     state = {
       ...state,
       keyserverStore: {
         ...state.keyserverStore,
         keyserverInfos: {
           ...state.keyserverStore.keyserverInfos,
           [ashoatKeyserverID]: {
             ...state.keyserverStore.keyserverInfos[ashoatKeyserverID],
             sessionID: action.payload.sessionChange.sessionID,
           },
         },
       },
     };
   } else if (
     (action.type === logOutActionTypes.success &&
       invalidSessionDowngrade(
         oldState,
         action.payload.currentUserInfo,
         action.payload.preRequestUserState,
       )) ||
     (action.type === deleteAccountActionTypes.success &&
       invalidSessionDowngrade(
         oldState,
         action.payload.currentUserInfo,
         action.payload.preRequestUserState,
       ))
   ) {
     return oldState;
   }
 
   if (
     action.type !== updateNavInfoActionType &&
-    action.type !== setPrimaryIdentityKeys &&
-    action.type !== setNotificationIdentityKeys &&
-    action.type !== setPickledPrimaryAccount &&
-    action.type !== setPickledNotificationAccount
+    action.type !== setCryptoStore
   ) {
     const baseReducerResult = baseReducer(state, action, onStateDifference);
     state = baseReducerResult.state;
 
     const {
       storeOperations: { draftStoreOperations, reportStoreOperations },
     } = baseReducerResult;
     if (draftStoreOperations.length > 0 || reportStoreOperations.length > 0) {
       (async () => {
         const databaseModule = await getDatabaseModule();
         const isSupported = await databaseModule.isDatabaseSupported();
         if (!isSupported) {
           return;
         }
         const convertedReportStoreOperations =
           reportStoreOpsHandlers.convertOpsToClientDBOps(reportStoreOperations);
         await databaseModule.schedule({
           type: workerRequestMessageTypes.PROCESS_STORE_OPERATIONS,
           storeOperations: {
             draftStoreOperations,
             reportStoreOperations: convertedReportStoreOperations,
           },
         });
       })();
     }
   }
 
   const communityPickerStore = reduceCommunityPickerStore(
     state.communityPickerStore,
     action,
   );
 
   state = {
     ...state,
     navInfo: reduceNavInfo(
       state.navInfo,
       action,
       state.threadStore.threadInfos,
     ),
     cryptoStore: reduceCryptoStore(state.cryptoStore, action),
     communityPickerStore,
   };
 
   return validateState(oldState, state);
 }
 
 function validateState(oldState: AppState, state: AppState): AppState {
   if (
     (state.navInfo.activeChatThreadID &&
       !state.navInfo.pendingThread &&
       !state.threadStore.threadInfos[state.navInfo.activeChatThreadID]) ||
     (!state.navInfo.activeChatThreadID && isLoggedIn(state))
   ) {
     // Makes sure the active thread always exists
     state = {
       ...state,
       navInfo: {
         ...state.navInfo,
         activeChatThreadID: mostRecentlyReadThreadSelector(state),
       },
     };
   }
 
   const activeThread = activeThreadSelector(state);
   if (
     activeThread &&
     !state.navInfo.pendingThread &&
     state.threadStore.threadInfos[activeThread].currentUser.unread &&
     getVisibility().hidden()
   ) {
     console.warn(
       `thread ${activeThread} is active and unread, ` +
         'but visibilityjs reports the window is not visible',
     );
   }
   if (
     activeThread &&
     !state.navInfo.pendingThread &&
     state.threadStore.threadInfos[activeThread].currentUser.unread &&
     typeof document !== 'undefined' &&
     document &&
     'hasFocus' in document &&
     !document.hasFocus()
   ) {
     console.warn(
       `thread ${activeThread} is active and unread, ` +
         'but document.hasFocus() is false',
     );
   }
   if (
     activeThread &&
     !getVisibility().hidden() &&
     typeof document !== 'undefined' &&
     document &&
     'hasFocus' in document &&
     document.hasFocus() &&
     !state.navInfo.pendingThread &&
     state.threadStore.threadInfos[activeThread].currentUser.unread
   ) {
     // Makes sure a currently focused thread is never unread
     state = {
       ...state,
       threadStore: {
         ...state.threadStore,
         threadInfos: {
           ...state.threadStore.threadInfos,
           [activeThread]: {
             ...state.threadStore.threadInfos[activeThread],
             currentUser: {
               ...state.threadStore.threadInfos[activeThread].currentUser,
               unread: false,
             },
           },
         },
       },
     };
   }
 
   const oldActiveThread = activeThreadSelector(oldState);
   if (
     activeThread &&
     oldActiveThread !== activeThread &&
     state.messageStore.threads[activeThread]
   ) {
     const now = Date.now();
     state = {
       ...state,
       threadActivityStore: {
         ...state.threadActivityStore,
         [activeThread]: {
           ...state.threadActivityStore[activeThread],
           lastNavigatedTo: now,
         },
       },
     };
   }
 
   return state;
 }
diff --git a/web/selectors/socket-selectors.js b/web/selectors/socket-selectors.js
index 672650aa4..1f56f55bd 100644
--- a/web/selectors/socket-selectors.js
+++ b/web/selectors/socket-selectors.js
@@ -1,162 +1,157 @@
 // @flow
 
 import olm from '@commapp/olm';
 import _memoize from 'lodash/memoize.js';
 import { createSelector } from 'reselect';
 
 import {
   sessionIDSelector,
   urlPrefixSelector,
   cookieSelector,
 } from 'lib/selectors/keyserver-selectors.js';
 import {
   getClientResponsesSelector,
   sessionStateFuncSelector,
 } from 'lib/selectors/socket-selectors.js';
 import { createOpenSocketFunction } from 'lib/shared/socket-utils.js';
 import type {
-  OLMIdentityKeys,
-  PickledOLMAccount,
   SignedIdentityKeysBlob,
   IdentityKeysBlob,
+  CryptoStore,
 } from 'lib/types/crypto-types.js';
 import type {
   ClientServerRequest,
   ClientClientResponse,
 } from 'lib/types/request-types.js';
 import type {
   SessionIdentification,
   SessionState,
 } from 'lib/types/session-types.js';
 import type { OneTimeKeyGenerator } from 'lib/types/socket-types.js';
 
 import { initOlm } from '../olm/olm-utils.js';
 import type { AppState } from '../redux/redux-setup.js';
 
 const baseOpenSocketSelector: (
   keyserverID: string,
 ) => (state: AppState) => ?() => WebSocket = keyserverID =>
   createSelector(urlPrefixSelector(keyserverID), (urlPrefix: ?string) => {
     if (!urlPrefix) {
       return null;
     }
     return createOpenSocketFunction(urlPrefix);
   });
 
 const openSocketSelector: (
   keyserverID: string,
 ) => (state: AppState) => ?() => WebSocket = _memoize(baseOpenSocketSelector);
 
 const baseSessionIdentificationSelector: (
   keyserverID: string,
 ) => (state: AppState) => SessionIdentification = keyserverID =>
   createSelector(
     cookieSelector(keyserverID),
     sessionIDSelector(keyserverID),
     (cookie: ?string, sessionID: ?string): SessionIdentification => ({
       cookie,
       sessionID,
     }),
   );
 
 const sessionIdentificationSelector: (
   keyserverID: string,
 ) => (state: AppState) => SessionIdentification = _memoize(
   baseSessionIdentificationSelector,
 );
 
 const getSignedIdentityKeysBlobSelector: (
   state: AppState,
 ) => ?() => Promise<SignedIdentityKeysBlob> = createSelector(
-  (state: AppState) => state.cryptoStore.primaryAccount,
-  (state: AppState) => state.cryptoStore.primaryIdentityKeys,
-  (state: AppState) => state.cryptoStore.notificationIdentityKeys,
-  (
-    primaryAccount: ?PickledOLMAccount,
-    primaryIdentityKeys: ?OLMIdentityKeys,
-    notificationIdentityKeys: ?OLMIdentityKeys,
-  ) => {
-    if (!primaryAccount || !primaryIdentityKeys || !notificationIdentityKeys) {
+  (state: AppState) => state.cryptoStore,
+  (cryptoStore: ?CryptoStore) => {
+    if (!cryptoStore) {
       return null;
     }
 
     return async () => {
       await initOlm();
+      const { primaryAccount, primaryIdentityKeys, notificationIdentityKeys } =
+        cryptoStore;
       const primaryOLMAccount = new olm.Account();
       primaryOLMAccount.unpickle(
         primaryAccount.picklingKey,
         primaryAccount.pickledAccount,
       );
 
       const identityKeysBlob: IdentityKeysBlob = {
         primaryIdentityPublicKeys: primaryIdentityKeys,
         notificationIdentityPublicKeys: notificationIdentityKeys,
       };
 
       const payloadToBeSigned: string = JSON.stringify(identityKeysBlob);
       const signedIdentityKeysBlob: SignedIdentityKeysBlob = {
         payload: payloadToBeSigned,
         signature: primaryOLMAccount.sign(payloadToBeSigned),
       };
 
       return signedIdentityKeysBlob;
     };
   },
 );
 
 const webGetClientResponsesSelector: (
   state: AppState,
 ) => (
   serverRequests: $ReadOnlyArray<ClientServerRequest>,
 ) => Promise<$ReadOnlyArray<ClientClientResponse>> = createSelector(
   getClientResponsesSelector,
   getSignedIdentityKeysBlobSelector,
   (state: AppState) => state.navInfo.tab === 'calendar',
   (
       getClientResponsesFunc: (
         calendarActive: boolean,
         oneTimeKeyGenerator: ?OneTimeKeyGenerator,
         getSignedIdentityKeysBlob: ?() => Promise<SignedIdentityKeysBlob>,
         getInitialNotificationsEncryptedMessage: ?() => Promise<string>,
         serverRequests: $ReadOnlyArray<ClientServerRequest>,
       ) => Promise<$ReadOnlyArray<ClientClientResponse>>,
       getSignedIdentityKeysBlob: ?() => Promise<SignedIdentityKeysBlob>,
       calendarActive: boolean,
     ) =>
     (serverRequests: $ReadOnlyArray<ClientServerRequest>) =>
       getClientResponsesFunc(
         calendarActive,
         null,
         getSignedIdentityKeysBlob,
         null,
         serverRequests,
       ),
 );
 
 const baseWebSessionStateFuncSelector: (
   keyserverID: string,
 ) => (state: AppState) => () => SessionState = keyserverID =>
   createSelector(
     sessionStateFuncSelector(keyserverID),
     (state: AppState) => state.navInfo.tab === 'calendar',
     (
         sessionStateFunc: (calendarActive: boolean) => SessionState,
         calendarActive: boolean,
       ) =>
       () =>
         sessionStateFunc(calendarActive),
   );
 
 const webSessionStateFuncSelector: (
   keyserverID: string,
 ) => (state: AppState) => () => SessionState = _memoize(
   baseWebSessionStateFuncSelector,
 );
 
 export {
   openSocketSelector,
   sessionIdentificationSelector,
   getSignedIdentityKeysBlobSelector,
   webGetClientResponsesSelector,
   webSessionStateFuncSelector,
 };
diff --git a/web/selectors/tunnelbroker-selectors.js b/web/selectors/tunnelbroker-selectors.js
index a83868b9d..e39d3b0c1 100644
--- a/web/selectors/tunnelbroker-selectors.js
+++ b/web/selectors/tunnelbroker-selectors.js
@@ -1,30 +1,30 @@
 // @flow
 
 import { createSelector } from 'reselect';
 
 import type { ConnectionInitializationMessage } from 'lib/types/tunnelbroker/session-types.js';
 
 import type { AppState } from '../redux/redux-setup.js';
 
 export const createTunnelbrokerInitMessage: AppState => ?ConnectionInitializationMessage =
   createSelector(
-    state => state.cryptoStore.primaryIdentityKeys?.ed25519,
+    state => state.cryptoStore?.primaryIdentityKeys.ed25519,
     state => state.commServicesAccessToken,
     state => state.currentUserInfo?.id,
     (
       deviceID: ?string,
       accessToken: ?string,
       userID: ?string,
     ): ?ConnectionInitializationMessage => {
       if (!deviceID || !accessToken || !userID) {
         return null;
       }
       return ({
         type: 'ConnectionInitializationMessage',
         deviceID,
         accessToken,
         userID,
         deviceType: 'web',
       }: ConnectionInitializationMessage);
     },
   );