SigilStateStore

@Singleton
class SigilStateStore @Inject constructor(context: Context)

Single source of truth for sigil identity persistence.

Owns the sigil_identity SharedPreferences file that previously lived inside SigilPanelViewModel. Pulled into core:identity so non-UI consumers — WalletSeedSource (sdk:wallet-seed), future agent runtimes — can query "is a sigil forged?" without taking a dependency on :sdk:dapp-ui.

Schema:

  • diddid:key derived from the passkey's compressed P-256 pubkey

  • credentialId — Credential Manager's opaque credential identifier

  • publicKeyHex — compressed P-256 pubkey, hex

  • backupDismissed — user chose "start fresh" over restoring a cloud backup; suppress the prompt on subsequent launches

Durability contract: writes use .commit() rather than .apply(). The restore flow SIGKILLs the process within a few ms of writing the sigil triple (see docs/security/SECURITY_NOTES.md 2026-05-18 entry). .apply()'s async write doesn't fsync before the kill, so the next launch reads an empty file and the sigil pill shows "no sigil" despite a successful restore. .commit() blocks until durable — cost is negligible since this runs once per forge / restore, not on a hot path.

Visibility: all DID + credentialId + pubkey are PUBLIC material. The passkey's private half never leaves the device's authenticator store. SharedPreferences MODE_PRIVATE is sufficient.

Constructors

Link copied to clipboard
@Inject
constructor(context: Context)

Types

Link copied to clipboard
object Companion

Properties

Link copied to clipboard
val snapshotFlow: StateFlow<SigilSnapshot?>

Observable view of the persisted sigil triple — emits the current value on subscribe + a new value after every persistSigil or clear call.

Functions

Link copied to clipboard
fun clear()

Drop the sigil triple. The cloud backup (Block Store) is NOT affected — only this local pointer to "we have a sigil." Use during wallet reset / restore-from-fresh flows.

Link copied to clipboard

Credential Manager identifier, or null when no sigil.

Link copied to clipboard
fun getDid(): String?

did:key for the forged sigil, or null when no sigil.

Link copied to clipboard

Compressed P-256 pubkey hex, or null when no sigil.

Link copied to clipboard

True when a sigil has been forged (or restored). Cheapest gate — checks the credential id field which is set last in the persistence atomic, so its presence implies a complete triple.

Link copied to clipboard

True when the user chose "start fresh" from the backup prompt.

Link copied to clipboard

Mark the cloud-backup prompt dismissed so future launches don't keep re-asking. Cloud blob itself stays — the user can still restore later from the SigilStatus.None sheet.

Link copied to clipboard
fun persistSigil(did: String, credentialId: String, publicKeyHex: String)

Persist the sigil triple atomically — see the class-level "durability contract" KDoc for the .commit() rationale.

Link copied to clipboard

Snapshot of the persisted sigil triple, or null when no sigil is forged. Convenience for consumers that want to load all three fields atomically (the restore flow's hydration step).