Skip to content
Explainers

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:

  • maxRounds stops after that many rounds. The result's caughtUp says whether it finished.
  • signal stops it between rounds when an AbortSignal fires.
  • onProgress hears 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 unregistered before registration. Until your user registers, there is nothing to read.

Last updated

On this page