Private balances
A private balance is a set of notes, each like a small token account that only its owner can read.
On Solana, a token balance lives in a token account. Anyone can read its owner, its mint and its amount. A private balance holds the same three facts, but only its owner can read them.
A balance is a set of notes
A private balance is made of notes. Each note is like a small token account: it has an owner, a token and an amount. Notes are stored on Solana, sealed so that only the owner's keys can open them.
A user's balance in a token is the sum of their notes in that token. Alice holds three USDC notes:
flowchart LR a["Note: 10 USDC"] --> b(["Private balance: 25 USDC"]) c["Note: 10 USDC"] --> b d["Note: 5 USDC"] --> b
Nobody else can see these notes as Alice's. To an observer they are three sealed records among everyone else's.
Spending makes new notes
A payment never edits a note. It consumes some of the payer's notes and creates new ones.
Say Alice pays Bob 10 USDC. The SDK spends up to three of her largest notes in one payment, so here it spends all three, 25 USDC in total. It creates two new notes: 10 USDC for Bob, and 15 USDC back to Alice as change. Fees are left out to keep the sums simple.
Alice's balance is now one 15 USDC note. Bob's balance has gained a 10 USDC note.
Why the device keeps a copy
Finding a user's notes takes their keys, and the keys stay in their browser. So the SDK finds the notes on the device. It reads new pool activity, tries the user's keys on each new note, and keeps the ones that open.
It stores what it finds in IndexedDB, one database per account. Every tab of your app shares it.
readBalances reads this copy and fetches nothing. Bringing the copy up to date is a
sync.
The states of a balance
readBalances returns one entry per token and state:
| State | What it holds |
|---|---|
available | Notes your user can spend now. |
pending | Notes not yet confirmed on Solana, or not yet past the slot they become spendable from. |
reserved | Notes a payment is spending. The payment may be running, stopped or sent and not yet settled. A deposit that merges notes reserves them too. |
expired | Notes past the last slot they could be spent in. |
A payment reserves every note it spends, change included. While Alice pays Bob 10 USDC, all 25 USDC show as reserved. Tabs and reserved funds explains why.
What this means for your app
- Sync before you show a balance. The copy is only as fresh as the last sync.
- A new device starts empty. It shows nothing until its first sync has read the user's notes back.
- Show the states apart. Show
availableas the balance, andpendingandreservedbeside it.
Last updated