Psy Wallet · the ZK-native wallet for the Psy chain

A wallet built for private, scalable on-chain payments.

Send public or fully-private transfers. Auto-claim incoming funds. Bridge from Ethereum. Manage multiple accounts. All inside a Chrome extension that runs ZK proofs locally and never leaks your keys.

Default privacy
ZK-secured
Proof system
Plonky2
Network
Psy chain · Ethereum bridge

Capabilities

Everything you need for private + public on-chain payments.

01

Wallet creation & import

Spin up a fresh wallet, import a 12-word mnemonic, restore from an encrypted backup, or build a scoped SD Key for apps and automation.

  • ZK Wallet (recommended) — private by default, ZK-secured.
  • Classic Wallet (secp256k1) — compatible with existing seed phrases & hardware.
  • SD Key Wallet — scoped key for apps & automation, limited to what you authorize.
  • Import: 12-word mnemonic, raw private key, or full backup JSON.
  • Multiple accounts in one wallet; switch with one click.
02

Private transfers

Send funds privately to a recipient's shield address. The amount, sender, and recipient are hidden on-chain. The recipient is notified over Nostr; a backup packet is downloadable as a fallback.

  • Shield address + npub recipient notation, or combined `shield#npub` paste.
  • ZK note proof generated locally — secrets never leave the device.
  • Nostr (NIP-44 / NIP-59 gift-wrap) delivers the claim packet automatically.
  • Saved backups page for every private send — re-download or retry proof at any time.
  • Auto-claim: spend pending balances and send privately in one signature.
03

Public transfers

Send by Psy ID with the speed and clarity of a normal account-based chain. UPS bundles claims and the transfer into a single proof, so one signature spends many sources.

  • Send by Psy-NNNNNNNN identifier or shorthand userId.
  • Auto-claim incoming public + private + shield-deposit balances in the same UPS.
  • Single guta_fee per UPS regardless of how many calls ride inside it.
  • Validations cover invalid Psy IDs, self-sends, zero amounts, insufficient balance.
04

Deposits from Ethereum

Move USDT (and other supported tokens) from Sepolia/Ethereum to the Psy chain through the bridge. The wallet shows the full settlement trail end-to-end.

  • MetaMask handshake — approve USDT, sign deposit.
  • Settlement trail: Submitted → Confirmed (10 blocks) → Tree Updated → Proof assembling → Claimable.
  • Shield-deposit claims flow into the wallet's Activity tab.
  • Bridge proofs are recursively aggregated up to 65,536 leaves per UPS session.
05

Claims (public, private, shield-deposit)

Inbound funds arrive as claimable rows. Sweep them individually or use Claim All to consolidate. Already-claimed items reconcile silently and never duplicate.

  • Public claims for inbound `simple_transfer`.
  • Private claims that verify the inclusion proof + retire the nullifier.
  • Shield-deposit claims after a bridge deposit lands on Psy.
  • Claim All batches everything in one UPS with a single fee.
  • Friendly fallback: if claim batch fails, the wallet retries the transfer alone (commit 49044fc).
06

Balance management & tokens

PSY and USDT ship by default. Add custom tokens by contract id. Per-token balances render with the correct decimals; the home card shows total available with the fee floor subtracted for native sends.

  • PSY (contract 0, 9 decimals) and USDT (contract 4, 6 decimals) by default.
  • Add / remove custom tokens — PSY cannot be removed.
  • Available = on-chain settled + claimables − native fee floor.
  • Token icons resolve from the symbol; custom tokens fall back to a glyph.
07

Transaction history (Activity)

Every operation lands in the Activity tab with status, amount, counterparty, fee, and a one-glance privacy badge. Batch operations expand to one row per recipient.

  • Status palette: Pending (spinner), Confirmed (foreground), Failed (red).
  • Pre-claim helpers collapse into the primary user-intent row.
  • Multi-recipient batches EXPAND to N rows (one per primary).
  • Self-transfer renders as 'Sent to self'.
  • Faucet auto-detected from operator userId and labelled accordingly.
08

Self-transfers, done right

Sending to your own Psy ID is allowed at the chain level but almost always a typo. The wallet renders it as 'Sent to self' so it's never mistaken for an incoming credit.

  • Wallet-side: detect isFromMe && isToMe and force outgoing styling.
  • Chain-side: companion fix surfaces the slot-balance reconciliation correctly (commit 33d1805).
  • Net result: no phantom 'incoming' rows after a self-send.
09

Saved backups & recovery

Every private send saves a recovery stub the instant the chain commit lands — so closing the popup mid-flight never bricks a transfer. Pending-proof rows can rebuild from stored secrets.

  • Recovery stubs persisted at chain-commit with full proof secrets.
  • Status badges: Delivered, Needs manual delivery, Proof failed — retry.
  • Re-download the packet at any time; recipient imports it under Claim → Import.
  • Retry Proof rebuilds an inclusion proof from stored secrets if the live RPC blipped.
10

Inbox & notifications

A background drain pulls Nostr gift-wraps targeted at every account's npubs. New private notes surface as a bell badge and an Inbox row, ready to claim.

  • Per-account Nostr drain; each account's drain is isolated.
  • Notification bell badge for new inbound private notes.
  • Inbox row shows sender label, amount, token, and a one-tap Claim button.
  • Persistent claim list caches across reloads (commit 7bccb96).

How it works

From install to first payment in under a minute.

Each step below corresponds to a real screen in the wallet. The flow is the same regardless of whether you're sending public or private.

01

Install

Download the Chrome extension. The wallet's WASM proof system initializes locally on first run; no remote keys, no cloud sync.

02

Create or import

Spin up a fresh ZK Wallet, import a 12-word mnemonic, restore an encrypted backup, or paste a private key. Multiple accounts share one password.

03

Receive

Share your Psy-NNNNNNNN for public payments or your shield address (and npub) for private ones. The first private receive address is created automatically at registration.

04

Send public or private

Toggle between public (by Psy ID) and private (by shield address) modes. The wallet auto-claims any pending inbound balances in the same UPS to fund the send.

05

Claim

Inbound public transfers, private notes, and shield deposits land in your Activity feed. Claim individually or sweep everything with Claim All.

06

Back up

Export an encrypted backup any time. Restore it into a fresh browser profile to recover every account, balance, note, and Activity row.

Security

Privacy is the default. Secrets never leave the device.

The wallet's threat model assumes a hostile network and a curious dApp. ZK proofs are computed locally inside a WASM prover; private keys are encrypted at rest by your password.

Local ZK proofs

Plonky2 + Poseidon over Goldilocks. The full prover runs inside the extension's MV3 service worker. Inputs are never transmitted to a remote prover; only proofs are submitted on-chain.

Password-encrypted keys

Mnemonics and private keys are encrypted at rest with a KDF-derived key from your password. View mnemonic requires the password every time.

Approval-based dApp access

Every dApp request goes through an approve popup. You see the contract, method, and inputs before signing. Internal wallet calls bypass the popup with an explicit isInternal check.

Origin-pinned permissions

Account access is granted per-origin. A dApp that's never been approved can't query account state. Permission grants are persisted; revocation is a one-click setting.

Nullifier-protected private notes

Every private note carries a unique nullifier. The chain rejects replay attempts; the wallet never reveals which note funded a transfer.

Recovery stubs at chain commit

Private transfer secrets are persisted to local storage the instant the chain commit lands — so a popup close or SW eviction mid-flight cannot brick a transfer. Retry proof rebuilds from stored secrets.

No L1/L2 conflation

Psy is an independent chain, not a rollup of Ethereum. The wallet refers to chains by name (Psy, Ethereum). Deposits and withdrawals are explicit, not implicit 'L1/L2' moves.

Atomic batches

UPS commits all operations in a single transaction. If any call fails, the whole batch unwinds — no half-state. Your Activity tab reflects the atomic outcome.

Architecture

Built on UPS, Plonky2, and Poseidon.

Psy Wallet is a Chrome MV3 extension that talks to the Psy chain via a configurable prove-proxy and to Ethereum via the bridge UI. The same WASM prover powers single sends, batches, and shield-deposit claims.

UPS (Unified Proof System)

One signature, one ZK proof, many contract calls. Auto-claim batches incoming balances with the outgoing transfer in a single transaction. Pays the base fee once.

Plonky2 + Goldilocks

Recursive ZK proofs over the Goldilocks field. Proof generation is parallelisable and runs locally; recursive aggregation lets the bridge prove batches up to 65,536 leaves per session.

Poseidon

The ZK-friendly hash used for commitments and Merkle trees. Tuned for Goldilocks to keep proof sizes small and verification fast.

Nostr (NIP-44 / NIP-59)

Encrypted gift-wrap delivers private-note claim packets to recipient npubs. Multi-relay; the wallet's background drain pulls notes targeted at every account's address.

MV3 service worker

The WASM prover, message bus, and state manager all live in the SW. Cold-boot path is hardened: refreshPsyState awaits the in-flight reload instead of replying with stale 'initializing' state.

extStorage (chrome.storage.local)

Wallets, mnemonics, claim caches, Activity history, and transfer backups are persisted here. Survives popup close, SW eviction, and browser restart.

FAQ

Frequently asked questions.

Is Psy Wallet open source?+

The wallet ships with full source under github.com/PsyProtocol/psy-wallet. Reproducible builds are produced on the feat/shield-poseidon-bridge branch and verified by the e2e suite under e2e/.

What chains does Psy Wallet support?+

Native: Psy chain (its own ZK-native independent chain). Bridged: Ethereum (and testnets like Sepolia) via the bridge UI for deposits and withdrawals of supported tokens (PSY, USDT).

Do you store my private keys?+

Never on a server. Keys are encrypted at rest in chrome.storage.local on your device using your password as the KDF input. The wallet never transmits keys to any remote endpoint.

Are private transfers traceable?+

On-chain, no. The note commitment hides sender, recipient, and amount. The recipient receives a claim packet via Nostr (or via a downloaded backup as a fallback). Only the recipient can identify the inbound credit.

What happens if I close the popup mid-transaction?+

Public transfers commit atomically on-chain — closing the popup after the signature doesn't affect the chain outcome. Private transfers persist a recovery stub the instant the chain commit lands, so you can Retry Proof or download the backup later.

How do I recover my wallet on a new device?+

Export a backup from Settings → Export Wallet, restore it on the new device with the same password. Every account, balance, note, shield address, and Activity row recovers.

Can I send to multiple recipients at once?+

Yes — UPS supports batches up to 25 recipients per UPS in the current UI cap (structurally up to 65,536 per session). Each recipient can be public or private, and tokens can be mixed.

What does 'Sent to self' mean in my Activity?+

It's a small render of a public transfer where the recipient is your own Psy ID. The chain accepts these (and they cost the normal fee) but the wallet labels them so they aren't mistaken for incoming credits.