Database & storage¶
The SDK persists wallet state in SQLite. Three adapters auto-select based on environment; you can override.
Adapters¶
| Environment | Adapter | Backing store | Typical use |
|---|---|---|---|
| Browser | sql.js (WASM) |
IndexedDB | Web wallets |
| Node.js | better-sqlite3 |
File on disk | Servers, CLI tools |
| Tests | In-memory | RAM | Unit tests, CI |
The SDK picks the right adapter automatically. To force one:
new NavioClient({
databaseAdapter: 'better-sqlite3', // or 'browser' / 'indexeddb' / 'memory'
walletDbPath: './wallet.db',
});
Paths¶
| Adapter | walletDbPath meaning |
|---|---|
better-sqlite3 |
Filesystem path. Directory must exist. |
browser / indexeddb |
Logical name — becomes an IndexedDB database name. |
memory |
Ignored (or pass :memory: for clarity). |
Using WalletDB directly¶
For advanced cases:
import { WalletDB } from 'navio-sdk';
const db = new WalletDB({ type: 'better-sqlite3' });
await db.open('./wallet.db');
await db.createWallet(50000); // creationHeight
const keyManager = await db.loadWallet();
await db.close();
Memory → file migration¶
const memDb = new WalletDB({ type: 'memory' });
await memDb.open(':memory:');
await memDb.createWallet();
// Later:
const persistent = await memDb.migrate('./wallet.db');
Encrypted export / import¶
const blob = await db.exportEncrypted('backup-pw');
// ... save to disk / upload to S3 ...
const restored = await WalletDB.loadEncrypted(blob, 'backup-pw');
Plaintext export:
Check whether a blob is encrypted:
Schema¶
Simplified — see navio-sdk source for the authoritative SQL.
Key management¶
| Table | Columns |
|---|---|
keys |
key_id, pub_key, priv_key |
crypted_keys |
key_id, pub_key, encrypted_secret |
out_keys |
out_key_id, pub_key, priv_key |
crypted_out_keys |
out_key_id, pub_key, encrypted_secret |
view_key |
view_key (blob) |
spend_key |
spend_key (blob) |
master_seed |
mnemonic / seed (plaintext or encrypted) |
hd_chain |
chain_index, sub_addr_index, per-account counters |
sub_addresses |
(account, index) → DPK |
Outputs & sync¶
| Table | Columns |
|---|---|
wallet_outputs |
See below |
tx_keys |
(block_height, output_hash) → tx-key payload (optional, retained if keepTxKeys) |
block_hashes |
Ring buffer of recent block hashes for reorg detection |
sync_state |
last_synced_height, last_synced_hash, chain_tip_at_last_sync, last_sync_time |
wallet_metadata |
creation_height, creation_time, version |
encryption_metadata |
salt, verification_hash |
wallet_outputs¶
CREATE TABLE wallet_outputs (
output_hash TEXT PRIMARY KEY,
tx_hash TEXT NOT NULL,
output_index INTEGER NOT NULL,
block_height INTEGER NOT NULL,
output_data TEXT NOT NULL,
amount INTEGER NOT NULL DEFAULT 0,
memo TEXT,
token_id TEXT,
blinding_key TEXT,
spending_key TEXT,
is_spent INTEGER NOT NULL DEFAULT 0,
spent_tx_hash TEXT,
spent_block_height INTEGER,
created_at INTEGER NOT NULL
);
Browser storage specifics¶
sql.js keeps the DB fully in memory during the session. Changes are debounced and persisted to IndexedDB, so reloads do not lose state. The entire DB blob is stored as a single IndexedDB record — large wallets (many tens of thousands of outputs) can take noticeable time to load.
For very large browser wallets, consider:
- Offloading cold storage to a backend (encrypted export + server-side store).
- Splitting the wallet — maintain separate NavioClient instances per account.
Optimisation knobs¶
| Option | Default | Effect |
|---|---|---|
keepTxKeys |
false |
Keep tx_keys rows after processing — larger DB, faster resync |
blockHashRetention |
10000 |
Cap on block_hashes ring buffer |
saveInterval |
100 |
Persist every N blocks during sync |
creationHeight |
tip − 100 | Skip history before this block |