pocket
Reference

Configuration and storage keys

Every environment variable, every network field, and every key the wallet writes to disk, with what each one holds.

A lookup table. Configuration and environment explains the reasoning behind these; this page is the list.

Build-time variables

Read at build time from extension/.env, and never committed. Absent, each one makes the wallet report the feature as unconfigured rather than failing at a fetch.

VariableHoldsAbsent means
VITE_ARCHIVE_URLthe durable event archive's base URLprivate history and rebuild-from-history report themselves unavailable, and the controls are hidden
VITE_DEFINDEX_API_KEYthe yield service API keyyield reports "not configured for this network"
VITE_DEFINDEX_VAULTthe vault contract to deposit intothe same

.env loads on every build. .env.production loads afterwards for a production build and overrides only what it sets.

Aquarius, CCTP and the asset directory need no configuration. All three are keyless.

Network fields

One entry per network in extension/src/core/config.ts.

FieldTypeHolds
id"testnet" | "mainnet"which network this entry is
passphrasestringthe network passphrase every signature commits to
rpcUrlstringSoroban RPC
horizonUrlstringHorizon
friendbotUrlstring, optionalthe testnet faucet. Absent on mainnet by design
nativeSacstringXLM's Stellar Asset Contract
knownAssetsarray, optionalcredit assets the public pocket surfaces when a trustline exists
confidentialarrayone entry per private asset. Empty means the private pocket is unavailable
archiveUrlstring, optionalthe archive, from the build-time variable
defindexobject, optional{ baseUrl, vault?, apiKey? }
aquariusobject, optional{ apiUrl, router }

A knownAssets entry is { code, issuer }. The Stellar Asset Contract id is derived rather than stored, and a trustline the account does not hold is omitted rather than shown as zero.

A confidential entry

FieldHolds
tokenthe wrapper contract. Its address is baked into every key derived for it
verifierthe UltraHonk verifier. Shared across wrappers
auditorthe auditor key registry. Also shared
underlyingthe SEP-41 asset this wrapper holds
symbolthe display symbol

What the wallet writes to disk

All of these live in chrome.storage.local, and everything sensitive among them is encrypted.

KeyHoldsEncrypted
pocket.vaultthe vault header: version, KDF parameters, salt, wrapped data keythe wrapped key is
pocket.statethe recovery phrase, sealed under the data keyyes
pocket.settings{ network, autoLockMinutes? }no
pocket.inflighta submitted transaction whose outcome is not yet knownno
pocket.stagedthe local consequence of a submission, written before it is sentyes
pocket.openingsthe (value, randomness) pairs that make private balances spendableyes
pocket.addressthis wallet's public addressno, and deliberately
pocket.dappsleft behind by builds that stored connection grants on disk. Swept on eraseno
pocket.auditoridthe auditor id this account registered its own key underno

Three of these are worth reading twice

pocket.openings is not a cache. The chain stores commitments; only these pairs make one spendable. Discarding them makes funds visible on chain and permanently unspendable. That is why the extension requests unlimited storage and why the archive exists.

The key carries both the wrapper and the account, so it is enumerated rather than named:

pocket.openings.<token>.<address>

The format lives in one function, because a caller that builds the string itself can drift from the one that enumerates. Both failure modes are silent: a read that misses reports no record of your balances, and an erase that misses leaves a blob no future key can open.

pocket.address is in the clear on purpose. It is on the ledger the moment the account is funded, so storing it plainly reveals nothing. It exists so a user who has forgotten their password can still be checked against the wallet they are trying to erase, which is the only way to authorise that erase without the password.

pocket.auditorid has to be recorded because the registry allocates the id and returns it. Losing it does not lose funds, but it orphans a registered key and the next attempt allocates another, so a retry reuses this. It is per deployment, per account, and enumerated for the same reason openings are.

What lives in RAM

KeyWhereHolds
pocket.sessionchrome.storage.sessionthe data key in base64, plus the lock deadline
the connection grantschrome.storage.sessionwhich origins may see your address and ask you to sign

chrome.storage.session is RAM-backed, wiped on browser close, and restricted to trusted extension contexts.

The seed is deliberately absent from it. The plaintext seed lives in service-worker memory only and is never written anywhere, not even here. What is mirrored is the one value needed to re-open the vault, so a routine worker eviction does not force the password again while a real lock still does.

The vault and locking.

What the popup writes

One key, and it is in the popup's own localStorage rather than in extension storage:

KeyHolds
pocket:savedAddressesup to 20 addresses this device has paid, most recent first

The addresses themselves are public on the ledger, which is why they are stored in the clear. Who this device paid is not public, and that is what the list is, so erasing the wallet clears it. It is cleared explicitly, because the worker's sweep over chrome.storage.local cannot reach the popup's localStorage.

What an erase removes

In this order, and the order is load-bearing:

pocket.vault  pocket.state  pocket.inflight  pocket.staged
pocket.address  pocket.dapps  every pocket.openings.*  every pocket.auditorid.*

Vault first, openings last. A process kill part way through leaves orphaned blobs and no vault, which a fresh install sweeps. The reverse would leave a working wallet whose openings are gone, which means funds visible on chain and permanently unspendable.

Chrome documents the multi-key form but does not promise atomicity, so this is one window rather than a transaction.

Auditor ids survive when the same account is coming back, and only then.

Archive environment

VariableDefaultHolds
CONTRACT_IDrequired for backfillthe wrapper to ingest
DB_PATHpocket-archive.dbthe SQLite file
PORT8787the HTTP port
RPC_URLtestnet Soroban RPCwhere events are read from
HORIZON_URLtestnet Horizonwhere transfer invocation payloads are read from
ARCHIVE_ALLOWED_ORIGIN*the CORS origin

HORIZON_URL is not optional in practice. Without it, transfer payloads are not stored and every recipient rebuilding from the archive is refused.

Script environment

VariableDefaultUsed by
NETWORKtestnetdeploy, add-asset, infrastructure check
SOURCEpocket-deploythe signing account for deploys and TTL extensions
UNDERLYING, SYMBOLrequiredadd-asset.mjs
WARN_DAYS30the TTL threshold the infrastructure check extends below
EXTEND500000ledgers to extend by
NARGO, BB/tmp/nargo-beta11, /tmp/bb-0.87.0release gate 1 and 2

Test environment

VariableHolds
POCKET_EXT_PATHrun the suite against a different build
POCKET_TESTNET_SECRETa funded testnet account for the live tiers
POCKET_LIVE_E2Eopt in to tests that submit real transactions
POCKET_TEST_ARCHIVE_URLthe archive the suite points at
QA_AMBIENTreport or fail
PW_WORKERSbrowser test concurrency

On this page