Overview
SubWallet employs a multi-layer state management architecture:- Chrome Storage Stores - Persistent storage for background service
- Redux Store - Client-side state management in UI
- Service State - In-memory state in background services
- Subscriptions - Real-time state synchronization
Architecture
Chrome Storage Stores
BaseStore
The foundation for all persistent storage in the background. Location:packages/extension-base/src/stores/Base.ts
packages/extension-base/src/stores/Base.ts:14-81
Key Features:
- Namespaced keys with prefix
- Async callback-based API
- Chrome storage.local backend
- Type-safe value storage
SubscribableStore
Extends BaseStore with RxJS subscription support. Location:packages/extension-base/src/stores/SubscribableStore.ts
packages/extension-base/src/stores/SubscribableStore.ts:7-30
Key Features:
- RxJS Subject for reactive updates
- Emits on every
set()call - Promise-based
asyncGet()helper - Batch removal support
Built-in Stores
Location:packages/extension-base/src/stores/
packages/extension-base/src/stores/Accounts.ts:9-24
Redux Store (UI)
Store Configuration
Location:packages/extension-koni-ui/src/stores/index.ts
packages/extension-koni-ui/src/stores/index.ts:4-110
Store Categories
Base Stores
accountState: Account list, current account settings: UI settings, theme, language requestState: Authorization, signing requests uiViewState: UI state, modals, navigation staticContent: Static content, campaignsFeature Stores
balance: Account balances price: Token prices transactionHistory: Transaction history staking: Staking positions earning: Yield positions nft: NFT collections and items swap: Swap pairs and quotes crowdloan: Crowdloan contributionsCommon Stores
chainStore: Chain info, metadata, state assetRegistry: Token/asset registryRedux Toolkit Slices
Example slice structure:State Synchronization
Background to UI Subscriptions
Location:packages/extension-koni-ui/src/stores/utils.ts
DataContext Integration
Location:packages/extension-koni-ui/src/contexts/DataContext.tsx
packages/extension-koni-ui/src/contexts/DataContext.tsx:41-103
Common Patterns
Reading from Chrome Storage
Writing to Chrome Storage
Subscribing to Changes
Using Redux Store in Components
Awaiting Store Data
State Persistence
Chrome Storage (Background)
Persistent:- Survives extension restart
- Survives browser restart
- Shared across all extension contexts
- Quota: ~5MB (local storage)
- Account data
- Keyring
- Settings
- Authorization data
- Metadata
Redux Persist (UI)
Persistent (via localStorage):- Survives page refresh
- Lost on extension update (sometimes)
- Separate per popup instance
- Balance (refreshed on load)
- Transaction history (subscribed)
- NFTs (subscribed)
- Chain state (subscribed)
- Request state (ephemeral)
Best Practices
-
Use Appropriate Storage:
- Chrome Storage for critical data in background
- Redux for UI state
- Don’t duplicate data unnecessarily
-
Subscribe to Updates:
- Use SubscribableStore for reactive data
- Set up subscriptions in DataContext
- Clean up subscriptions on unmount
-
Await Store Readiness:
- Use
awaitStores()before rendering - Show loading states while waiting
- Handle loading errors gracefully
- Use
-
Type Safety:
- Define TypeScript types for all state
- Use RootState type for selectors
- Use PayloadAction for Redux actions
-
Performance:
- Don’t persist large datasets
- Use memoization for expensive selectors
- Batch updates when possible
-
Error Handling:
- Handle Chrome storage errors
- Validate data on read
- Provide fallbacks for missing data
Related Documentation
- Background Services - Service architecture
- Extension UI - Redux integration
- Message Passing - State synchronization