Unlinked

DocsPrivacy guide

No funding link. Keep it that way.

Unlinked removes one leak: the transaction that funds a fresh address from your main wallet. Everything else is up to how you use the address. This page lists what can still link it to you and what to do about each.

Threat model#

An observer reads the public ledger. The one thing Unlinked removes from it is the funding transaction: a fresh address never needs ETH, so nothing ever connects it to the wallet that would have paid for its gas.

ClearThe funding link

Main wallet0xA1f0…7e3B
funding tx · 0.002 ETH
Fresh address0x9c4e…a041

Funding a fresh address from your main wallet writes the link on the public ledger. Anyone can read it, forever.

SealedNo funding tx

Main wallet0xA1f0…7e3B
never sent
Fresh address0x9c4e…a041 · 0 ETH
pays its gas for a proof of work
PaymasterEntryPoint deposit

A proof of work pays instead. The main wallet stays public but is never connected: there is no link to read.

Example addresses. The fresh address holds 0 ETH before and after its first op, and nothing links it to the main wallet.

Do and don't#

  • Do create a fresh key for each identity, in a browser profile you don't use with your main wallet.
  • Do export the key (or save it encrypted) before closing the tab, and burn the identity when you are done.
  • Don't connect your main wallet in the same session. The app never asks you to.
  • Don't send ETH or tokens to the fresh address from your main wallet, and don't send them straight back. Either recreates the link Unlinked removes.
  • Don't use a unique amount. Round, common amounts blend in; 1,337.42 doesn't.
  • Do use Tor, or your own relay, if the relay operator seeing your IP address matters to you.

What leaks where#

What can leak, and what the stack does about it
LeakMitigation
IP address at the relayOne relay for everyone, no IP or body logs, zero retention. Use Tor, or run your own relay.
IP address at the chain RPCReads keyed to your address go only to the relay, and only when you ask. The chain RPC gets address-free reads.
EntryPoint nonce keyAlways key 0. viem's default key embeds Date.now(), your clock to the millisecond, on-chain; the relay rejects it.
Timing on-chainRelay-held delay (pow_sendUserOperation) and optional batch windows. Wait several epochs after funding a stealth address.
Timing and hashrate at the relayNo estimation call; the epoch is polled on a fixed interval, and any relay read a send must make first (a refetch after waiting for the next epoch, a resync) is followed by a random pause before mining.
PoW nonce patternsEach mining chunk starts at a random nonce.
Gas and fee fingerprintGas limits from fixed per-template profiles, fees from the epoch: every op of one template in one epoch looks the same, except PVG, shared per 30 s quote.
DelegateEveryone shares one delegate, Simple7702Account v0.9, enforced on-chain.
Authorization nonceVisible on-chain; a fresh key has 0. An imported key with history is already linkable by that history.
BrowserNever connect your main wallet. Burn the identity when done. A separate browser profile helps.
AmountsAvoid unique amounts and round trips back to your main wallet.

Reads keyed to your address#

A balance or nonce read tells whoever answers it that someone at your IP cares about that address. So:

  • The app sends every address-keyed read (pow_getAccountState) to the relay, which already sees your sends, and only when you import a key, press Refresh, or after a failed send (one read to resync the nonces). Nothing is polled.
  • A fresh key needs no read at all: its state is known locally (freshAccountState), and confirmed ops advance it.
  • The chain RPC only receives public, address-free reads: epoch parameters, stats and logs.
  • The epoch is polled on a fixed 60-second interval. A send normally mines from the last poll, so no read precedes mining. When the SDK must read the relay itself first (it waited for the next epoch and refetches it, its own first fetch without a shared poller, or a resync after a failure), it waits a random time (up to 20 s, less near the end of an epoch) before mining, so the relay can't time your mining from that read.

Relay-held delay#

pow_sendUserOperation asks the relay to hold your op for up to the epoch's remaining window before forwarding it, so its time on-chain is not the time you mined it. In the app: Privacy options → Relay-held delay. In the SDK: delaySec.

Exposure states#

Everything Unlinked shows is in one of three states, always named in words, never by colour alone: clear values anyone can read, masked values only their owner can reveal, and sealed values that never exist or are never shown.

Exposure states
StateMeansUsed forHow to reveal it
ClearAnyone can read it.Transaction and userOp hashes, blocks, epochs, explorer links, “0 ETH · never funded”, gas paid, work in bits, and the review table before you send.Nothing to reveal: it is public.
MaskedHidden from anyone looking at the screen. The owner can reveal it.In the app: your address, balances, amounts and counterparties. On /stats: the senders of sponsored ops (public on-chain, not displayed).Press and hold “Hold to reveal”, or press Space or Enter on it. It reseals when you let go, change screens, switch windows or hide the tab. Private view off shows values in full after a confirm.
SealedNever exists, or is never shown.The funding transaction (never sent). Your private key: Copy without display, or Show once for 10 s.It can't be revealed: there is nothing behind it, or it leaves only through Copy or Show once.
Example values · not an account
Address · masked
Example address: 0x9c4e2b7fd01e88a0…a041 (hidden on screen)
Balance · masked
Example balance: 1,204 (hidden on screen) mNVDA
Funding transaction · sealed
Never sent
Private key · sealed
Private key, never shown
A mask is a solid redaction bar over a decoy, never a blurred copy of the value: a blur of the real text could be reversed from a screenshot, a bar over a decoy cannot. Widths are fixed per value class, so length never leaks.

Revealing is always your act, and always brief: nothing lifts on hover or focus, copying never reveals, and every value reseals when you let go, change screens, switch windows or hide the tab. The mask hides values from people looking at your screen; it does not hide anything on-chain. What is on-chain is public, which is why the funding link is sealed rather than masked: it is never written at all.

Nonce key 0#

Standard ERC-4337 tooling (including viem's default) puts Date.now() in the EntryPoint nonce key, which publishes your clock, to the millisecond, on-chain. The SDK always uses key 0 and the relay rejects any other key.

Fingerprints#

Gas limits come from fixed per-template profiles and fees from the epoch, so every op of one template in one epoch is identical apart from the shared PVG quote. Everyone delegates to the same Simple7702Account v0.9. The miner starts each chunk at a random nonce, so solutions reveal nothing about your device.

The browser#

The key is generated in the tab and held in memory. Encrypted persistence is optional: AES-GCM under a key derived from your passphrase (PBKDF2-SHA256, 600,000 iterations), stored in IndexedDB without the address in the clear. Burn identity erases the key, the saved copy and the session's activity.