How Wallet Settings and User Preferences Are Stored in Nautilus Wallet
Nautilus Wallet persists global user preferences in the browser's extension storage (browser.storage.local) via the useWebExtStorage composable, while per-wallet settings like address reuse policies are stored in IndexedDB through the walletsDbService, with both layers synchronized through Pinia stores.
Nautilus Wallet is an open-source browser extension for managing Ergo blockchain assets. Understanding how wallet settings and user preferences stored in Nautilus Wallet persist across sessions requires examining its dual-layer architecture that separates application-wide configuration from wallet-specific behavior.
Global User Preferences in Extension Storage
Global preferences—such as UI theme, language, and zero-confirmation settings—apply to the entire extension instance. These values live in the browser's extension storage area and are managed reactively through Pinia.
The useWebExtStorage Composable
In src/stores/appStore.ts, the global settings object is initialized using the useWebExtStorage composable:
// src/stores/appStore.ts
const settings = useWebExtStorage<Settings>("settings", DEFAULT_SETTINGS, {
mergeDefaults: true
});
This composable, defined in src/composables/useWebExtStorage.ts, wraps the WebExtension Storage API (browser.storage.local). It serializes values using VueUse StorageSerializers and ensures that reads and writes are reactive within the Vue ecosystem.
Default Settings and Migration
Default values are defined in src/constants/settings.ts:
// src/constants/settings.ts
export const DEFAULT_SETTINGS = {
lastOpenedWalletId: 0,
isKyaAccepted: false,
conversionCurrency: "usd",
devMode: !MAINNET,
graphQLServer: DEFAULT_SERVER_URL,
explorerUrl: MAINNET ? "https://sigmaspace.io/en" : "https://testnet.ergoplatform.com",
ipfsGateway: "https://ipfs.io/ipfs/",
hideBalances: false,
blacklistedTokensLists: ["nsfw", "scam"],
zeroConf: false,
locale: "auto" as const,
colorMode: "auto" as const,
extension: { viewMode: "popup" as const },
ledger: { transport: "webusb" as const }
};
The extension includes migration logic to move legacy data from localStorage to the new extension storage. During initialization in appStore.ts, if isKyaAccepted is false but wallets exist, the store checks for old localStorage settings and migrates them before clearing the legacy storage.
Reading and Updating Global Preferences
To read a global setting, access the reactive ref through the app store:
import { useAppStore } from "@/stores/appStore";
import { computed } from "vue";
const appStore = useAppStore();
const isDarkMode = computed(() => appStore.settings.colorMode === "dark");
Updates are automatically persisted:
// Enable zero-confirmation transactions
appStore.settings.zeroConf = true;
// Changes are immediately written to browser.storage.local via useWebExtStorage
Per-Wallet Settings in IndexedDB
While global preferences apply to the entire extension, per-wallet settings control behavior specific to individual wallets, such as address reuse policies and change address indices. These are stored within the wallet's database record.
The WalletSettings Type and Database Schema
The type definition in src/types/internal.ts defines the structure:
// src/types/internal.ts
export type WalletSettings = {
avoidAddressReuse: boolean;
addressFilter: AddressFilter; // "all" | "active" | "unused"
defaultChangeIndex: number;
};
The database schema in src/types/database.ts nests these settings inside the wallet record:
// src/types/database.ts
export interface IDbWallet {
id: number;
name: string;
type: WalletType;
publicKey: string;
chainCode: string;
mnemonic?: string;
settings: WalletSettings; // Persisted per-wallet configuration
}
Persistence Flow via walletsDbService
When a wallet is created in src/stores/appStore.ts, default settings are embedded in the database record:
settings: {
avoidAddressReuse: false,
addressFilter: "all",
defaultChangeIndex: 0
}
The walletsDbService in src/database/walletsDbService.ts handles IndexedDB operations. When settings change, appStore.updateWallet triggers a partial update to the settings column of the wallet record.
Accessing Wallet-Specific Configuration
The walletStore in src/stores/walletStore.ts loads the wallet record and exposes a reactive settings ref:
// Inside walletStore load()
settings.value = wlt.settings;
Components bind directly to these reactive properties. For example, to check address reuse settings:
import { useWalletStore } from "@/stores/walletStore";
import { computed } from "vue";
const walletStore = useWalletStore();
const avoidReuse = computed(() => walletStore.settings.avoidAddressReuse);
Changes trigger automatic persistence through a deep watcher in walletStore.ts:
watch(
[name, settings, () => privateState.lastSynced],
async () => {
if (privateState.loading) return;
appStore.updateWallet(privateState.id, {
name: name.value,
lastSynced: privateState.lastSynced,
settings: toRaw(settings.value)
});
},
{ deep: true }
);
How the Storage Layers Interact
Nautilus Wallet maintains a strict architectural separation between global and wallet-specific configuration:
-
Global preferences in
browser.storage.localaffect the entire extension instance. These include theme settings, language, and global flags likezeroConf. They are accessible viaappStore.settings. -
Per-wallet settings in IndexedDB affect only the active wallet. These include address derivation policies and filters. They are accessible via
walletStore.settings.
The UI components in src/views/settings/SettingsView.vue and src/views/wallet/WalletSettings.vue read from the appropriate Pinia store based on whether the setting is global or wallet-specific. Writes flow back through the same stores, ensuring persistence happens automatically without manual database calls.
Summary
- Global user preferences are stored in
browser.storage.localvia theuseWebExtStoragecomposable and accessed throughappStore.settings. - Per-wallet settings are embedded in the
IDbWalletrecords in IndexedDB, managed bywalletsDbService, and exposed viawalletStore.settings. - Automatic persistence occurs through Pinia's reactivity system: global settings write immediately to extension storage, while wallet settings trigger IndexedDB updates through deep watchers.
- Migration support exists in
appStore.tsfor upgrading legacylocalStoragedata to the modern extension storage API.
Frequently Asked Questions
Where does Nautilus Wallet store theme and language preferences?
Theme and language preferences are stored in the browser's extension storage (browser.storage.local) as part of the global settings object. The useWebExtStorage composable in src/composables/useWebExtStorage.ts wraps this API, exposing a reactive settings ref in src/stores/appStore.ts that includes colorMode for themes and locale for language settings.
How are per-wallet address reuse settings persisted?
Per-wallet address reuse settings are stored in IndexedDB as part of the IDbWallet record. The WalletSettings type in src/types/internal.ts defines the avoidAddressReuse boolean, which is nested inside the IDbWallet interface from src/types/database.ts. When modified via walletStore.settings, a deep watcher triggers walletsDbService to update the specific wallet record in IndexedDB.
Does Nautilus Wallet migrate old localStorage data?
Yes. During initialization in src/stores/appStore.ts, the extension checks if isKyaAccepted is false while wallets exist in the database. If legacy localStorage data is detected, the store parses the old settings, merges them with DEFAULT_SETTINGS, writes them to browser.storage.local via useWebExtStorage, and clears the legacy localStorage to complete the migration.
Can I access wallet settings programmatically from a content script?
No. Wallet settings in IndexedDB and global settings in browser.storage.local are isolated to the extension's internal contexts. Content scripts run in the context of web pages and cannot directly access IndexedDB or extension storage without explicit permissions and messaging APIs. All programmatic access to settings should occur within the extension's background scripts or internal pages using the provided appStore and walletStore Pinia stores.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →