Keeping the device in sync
Why the device's copy of the private balance needs syncing, what a sync does, and when to run one.
A wallet app reads a token balance straight from an RPC node. A private balance cannot be read that way. Only your user's keys can find their notes, so the device finds them and keeps a copy.
A sync brings that copy up to date.
What a sync does
syncNoteStore runs in rounds until it has read everything new:
sequenceDiagram participant App as Your app participant SDK participant Nimbus as Nimbus indexer and Solana participant Store as This device App->>SDK: syncNoteStore loop until caught up SDK->>Nimbus: the next page of pool activity SDK->>SDK: try your user's keys on each new note SDK->>Store: save their notes and spends end SDK->>Store: release payments a closed tab left SDK-->>App: ingested
In each round, the SDK reads one page of new notes, spends and records for each pool. It keeps the notes your user's keys open. It marks their notes as spent once Solana shows them spent.
Last, it frees the notes of any payment whose tab closed before sending it.
A sync downloads every new note, not just your user's. So it never tells the indexer which notes are theirs.
When the SDK syncs for you
Every deposit, Private Send and withdrawal syncs first, by default. A followed Private Send or
withdrawal syncs again once it lands. Pass sync: false to a payment only if you synced just before.
When your app should sync
- On load, once the session is open, before you show a balance.
- When the tab regains focus, since your user may have been paid meanwhile.
- On an interval while the page is visible, to pick up incoming payments.
Every tab shares one copy. A sync in one tab updates the balance for all of them.
Long syncs
A device that has been away a while, or a new device, has a lot to read. Three options keep a sync in hand:
maxRoundsstops after that many rounds. The result'scaughtUpsays whether it finished.signalstops it between rounds when anAbortSignalfires.onProgresshears about each round, with the slot reached.
The next sync picks up where the last one stopped.
What this means for your app
- Show "updating" while a sync runs. Show the last balance meanwhile, not a spinner in its place.
- Never block a payment on your own sync. The payment syncs for itself.
- Expect
unregisteredbefore registration. Until your user registers, there is nothing to read.
Last updated