Back to experience

Conflux · Wallet Architecture Experiment

Wallet Core

A wallet does not have to begin as one object. It can grow from data.

I designed a database-centred wallet core: DB stores state, functions change it, and UI subscribes. Add a mnemonic account, and background pipelines derive its addresses under the supported chains' rules; queries update the interface. Started separately after BIM Wallet, the experiment explores how account relations, chain code and UI can be organized independently.

RxDB
runtime wallet data lives in the database
4
chain adapters implemented in source
3 layers
Vault → Account → Address
2 adapters
React and Vue data injection

9 chapters · 2m 33s

01

After BIM Wallet, I independently tested a functional wallet model

After completing BIM Wallet, I did not keep abstracting it into a generic edition, nor did I begin from a defect that had to be corrected. My interest in functional programming led me to consider and test a path I had not seen in mainstream wallets at the time: the database itself is wallet fact, Actions change it through explicit arguments, and UI subscribes to and projects it. BIM Wallet and Wallet Core are parallel approaches. The former actively organizes related data inside product actions; the latter writes independent facts to DB and lets pipelines derive relations afterward.

  • BIM Wallet: product flows actively organize related data and commit a batch
  • Wallet Core: a separate database-centred experiment with pipeline-derived relations
  • It began with an interest in functional programming, not a correction or upgrade of BIM Wallet

02

Object-based wallets start with an object; Wallet Core starts with a database

Object-based wallets usually keep accounts, networks and balances in a Controller or Store in memory. UI reads that object and selected data is then written to storage. Wallet Core reverses the order: data in RxDB is wallet state. Action functions change the database directly, while UI subscribes through the observe layer, so there is no parallel account or balance state to synchronize. WalletClass only creates the database, curries methods, registers chains and starts pipelines during initialization.

  • Object-based wallet: an in-memory object owns the main state; storage saves it
  • Wallet Core: the database owns the main state; actions and UI work around it
  • Both can update reactively; the difference is which one keeps the final data
  • React and Vue provide an analogy for distinct mental models: before learning APIs, understand where data lives and how it changes

03

Vault, Account and Address answer three different questions

Vault records where keys come from, such as a mnemonic or private key. Account uses hdIndex to identify which account under that Vault. Address connects one Account to one Chain and stores the address used there. Wallet Core keeps them in separate collections, so they can be queried by Vault, Account, Chain or Address. The cost is that references must remain complete and Address rows must not be missed or duplicated.

  • For one mnemonic, a Vault can contain multiple Accounts with different derivation indexes
  • Each Account derives Addresses under the supported chains' rules; the matrix shows derivable pairs
  • Imported private keys link only to compatible chains; a key rejected by a chain produces no Address there
  • After adding an Account or Chain, pipelines complete the derivable Address rows

04

Adding a network and adding a chain family are different tasks

Once EVM is supported, another EVM network only requires a new Chain record. A new family such as Solana or TON requires implementing and registering ChainMethods. In either case, after an Account or Chain is added or removed, RxDB pipelines create or remove matching Address rows. BIM Wallet performs the same task inside createAccount / createNetwork and commits one database batch. Wallet Core treats Address as data derived later, so retry, deduplication and repair are also required.

05

The wallet core runs wherever the database can run

When an object-based wallet moves to a browser, phone or desktop, it must decide how in-memory state is saved and synchronized across processes. Wallet Core already keeps accounts, chains, addresses and current selections in RxDB. Moving platforms means choosing an RxDB storage implementation available there, while account relations, action functions, pipelines and observe queries remain reusable. Each platform still needs its own UI and process communication. If RxDB storage is slow or limited on a platform, Wallet Core inherits that limitation.

06

Account relations work; the asset layer is still a design

The current source can answer “which Address does this Account use on this Chain,” but it has no Asset or Transaction collection and no working asset manager. The design proposed two data sources: a centralized indexer that returns a complete portfolio, or onchain queries for tokens selected by the user. Either result would be converted into one balance list and displayed by account, chain or token. This is a future design, not a delivered capability.

07

One state source; actions tested without a UI

Object-based wallets usually treat an in-memory object as the main state and write part of it to storage, so both copies must stay consistent. Wallet Core uses the database as runtime state: schemas, indexes, relations and queries operate on the same data, and actions receive dependencies through arguments. The existing addChain test directly calls addChain({ database }, chain), checks the returned config and generated ID, then checks that adding the same chain throws UniquePrimaryKeyError. No UI is needed. The test still initializes a database and the action writes data: testability comes from explicit dependencies, not from calling a side-effecting operation pure.

08

The cost is that the database and pipelines carry all the pressure

In-memory objects suit frequent temporary updates and can change several fields inside one method. Wallet Core hands that work to RxDB. High-frequency data may need an extra cache. After adding an account or chain, Address rows are completed later by an asynchronous pipeline rather than by the same action. Failures need retry, deduplication, repair and runtime monitoring. One rule may also be spread across schemas, action functions and pipelines.

09

This is a working architecture skeleton, not a complete wallet

The source currently runs Vault, Account, Address and Chain relations; Conflux, EVM, Solana and TON families; reactive queries; React / Vue adapters; and two password flows. Database migration, caching, pipeline recovery and monitoring still need work. Assets, transactions, BTC / Cosmos, Svelte, hardware wallets and WalletConnect are not implemented in this source snapshot. It proves that the mental model can run, not that a complete wallet is finished.

Original architecture artifacts

Original Wallet Core architecture diagram
Original system diagram: Database, methods, chain methods, WalletClass and framework injection.
Wallet Core Vault Account Address Chain relationship diagram
Original account ER diagram: Vault, Account, Address and Chain.

Sources and implementation scope

The architecture, account model, chain adapters and implementation status described here come from Wallet Core source, tests, examples, VitePress documentation and the Wallet Mental Model note. BIM Wallet is used only to contrast active orchestration inside an action with pipeline derivation after a write. Assets and transactions are explicitly marked as design work. MetaMask Controller + Storage provides the concrete object-based reference; the page does not claim that it cannot run across platforms.