Docs

What VERX hides, and what it does not.

VERX encrypts amounts using Solana's Token-2022 confidential transfer extension. A balance becomes an ElGamal ciphertext that only your viewing key opens. Moving one requires a proof that the amounts add up and lie in range, checked by ZkE1Gama1Proof11111111111111111111111111111, a program built into the validator.

~ devnet · audited: false · own program deployed: none

This runs against a Token-2022 mint created for testing, whose mint authority is a throwaway key. There is no mainnet deployment and nothing here has been audited by anyone.

It is not a mixer

  • VERX does not mix funds and has no shared pool.
  • It does not break the link between a wallet and its history.
  • It hides amounts. It does not hide who paid whom.
  • Nothing here has been audited, and the site does not claim otherwise.

How to use it

Five steps, and what each one costs

01 · CONNECT

Connect a wallet that can sign messages

Phantom, Solflare or Backpack, set to devnet. The wallet must be able to sign a MESSAGE, not just transactions: the viewing keys come from one message signature. A wallet without that cannot open a vault at all, and the app says so rather than failing later.

02 · UNLOCK

Unlock the vault with one signature

You sign the 18 bytes solana-conf-bal/v1. That signature derives your ElGamal keypair and your AES key, in the browser. Nothing is sent anywhere, and nothing is stored: a reload asks again. Treat that signature like a private key, because it is one: anyone who gets you to sign those bytes can rebuild your viewing keys forever.

03 · CONFIGURE

Create the confidential account, once

This writes your ElGamal public key into your token account. The app asks your wallet for the derivation signature a SECOND time first and refuses to continue unless both agree: a wallet that signs differently each time would write a key its own next session could not read, and no backup could recover it.

04 · SHIELD, THEN APPLY

Move a public balance into the confidential one

One transaction, one approval. The deposit amount is VISIBLE on chain; what becomes private is everything that happens to it afterwards. The credit arrives as pending and is not spendable until you apply it, which is the protocol stopping a sender from flooding your account with credits.

05 · SEND OR WITHDRAW

Four transactions, or three

A confidential send is 5 transactions and the same number of approvals; a withdrawal is 4. The proofs are built in your browser and staged in temporary accounts first, which is why there is more than one. Those accounts hold 0.01213104 SOL of rent while the flow runs and give it back when the last transaction closes them. Every one of them belongs to your wallet from the moment it exists, so if you close the tab halfway you can close them later and recover the rent: the Vault screen offers it.

Privacy, exactly

Exactly what each step hides

stephiddenvisible to anyone reading the chain
Connect walletthe balanceEverything. Nothing is private until an amount is encrypted.
Private vaultthe balanceThat the account exists, and that it is yours.
Shield amountsnothingThe deposit itself, and its amount, at the moment it is made.
Private sendthe amountThat you paid that recipient, and when. The amount is not.
WithdrawnothingThe withdrawal and its amount.
Activitythe balanceEverything in it: these are public transactions. What is NOT in it is anything another machine did.

A confidential transfer hides HOW MUCH. It does not hide WHO: both token accounts, the fee payer and the slot are ordinary public data. Shielding an unusual amount and withdrawing the same unusual amount later also links the two for anyone watching.

Keys, backup and recovery

Your wallet is the backup

  • Your viewing keys are derived from your wallet signature, so your wallet IS the backup. The same wallet on another machine derives the same keys and reads the same balance. There is no separate seed to write down, and VERX could not give you one.
  • Nothing is stored in the browser except a list of transactions this browser sent. No key, no signature, no ciphertext. A reload costs one signature.
  • Losing the wallet loses the viewing keys, and with them the ability to read or spend the confidential balance. A confidential balance cannot be recovered from a seed phrase alone by any other tool: it needs the same derivation.
  • Switching accounts in your wallet locks the vault immediately. A vault belongs to one account.
  • Any script running on this origin can ask your wallet to sign the derivation message. The page ships no third-party code and a content security policy stops it talking to anywhere but the RPC, which raises the cost of an injection. It does not make one harmless: approve that prompt only when you asked for it.

Signature phishing, and where the browser stops helping

Where the browser stops helping

  • The derivation signature is the viewing key. Any website can ask your wallet to sign the same 18 bytes. If you approve it somewhere else, that site can read this balance for as long as it exists, and there is no way to rotate the key: it comes from your wallet.
  • So read the prompt. VERX asks for a MESSAGE that says exactly solana-conf-bal/v1, never a transaction, and only on a page you opened yourself. A prompt for those bytes on a page you did not navigate to is an attack.
  • This page ships no third-party scripts and its content security policy lets it talk to nothing but the RPC, which raises the cost of an injected script. It does not remove it: the RPC must be reachable, and an RPC accepts arbitrary strings. Script injection on this origin is still fatal.
  • A browser extension with permission to read this page can read anything in it. So can anyone with your unlocked machine. The vault keys live in memory only, which bounds how long they are there, not who can reach them while they are.
  • Nothing is stored and nothing is logged: no key, no signature, no ciphertext, in no store, which is measured on every run of npm run probe-app.

What it cannot do

What it cannot do

limitdetail
Only devnet, and only against this one test mintShield, send and withdraw all run from the browser now, but against a Token-2022 mint created for testing whose authority is a throwaway key. No mainnet deployment exists, nothing has been audited, and a real mint would have to be configured with the confidential extension at creation time.
A multi transaction flow asks for one approval per transactionA transfer is five transactions and a withdrawal is four, because the proofs are staged in accounts before they are cited. Signing them all up front would be one prompt, and it was the first design, but a blockhash lives about sixty seconds and these have to land in order: a flow that expired halfway would leave accounts open and a balance mid-move. Correctness won, so each transaction gets a fresh blockhash and the screens say how many approvals to expect.
A confidential balance must stay under 2^32 base unitsMeasured: an ElGamal ciphertext of 4,294,967,295 decrypts in 0.09s and one of 4,294,967,296 fails outright, because reading a balance is a discrete log. A first devnet run shielded 250,000 tokens at 6 decimals, 58x over that, and the balance became permanently unreadable. With 6 decimals the ceiling is 4,294.967295 tokens per account.
Wrapped SOL cannot be shieldedSo11111111111111111111111111111111111111112 is owned by the CLASSIC Token program and carries no extensions. Confidential transfers need a Token-2022 mint created WITH the extension, so VERX uses its own mint.

Supported assets

One mint, and why

One devnet mint, created for testing with the confidential extension enabled: Aw4gxqPKJrrFpVqT5K7z5ndXWQrjWXwymGm8XDdSGFdz, six decimals.

  • Wrapped SOL cannot be shielded: So111…112 belongs to the classic Token program and carries no extensions. A mint must be created WITH the confidential extension to hold a confidential balance, which cannot be added later.
  • No mainnet asset is supported, because nothing is deployed to mainnet. The proof program itself does run there: measured 2026-10-16 on mainnet and devnet.
  • A confidential balance tops out at 281,474,976,710,655 base units while it is pending, because a pending balance is read from a 16 bit and a 32 bit ciphertext. The available balance is read by AES and has no such ceiling.

Status of each part

What is live, and what is not

featurestatusstill visible on chain
Connect walletliveEverything. Nothing is private until an amount is encrypted.
Private vaultliveThat the account exists, and that it is yours.
Shield amountsliveThe deposit itself, and its amount, at the moment it is made.
Private sendliveThat you paid that recipient, and when. The amount is not.
WithdrawliveThe withdrawal and its amount.
ActivityliveEverything in it: these are public transactions. What is NOT in it is anything another machine did.
Private swapplannedNot determined. This is why it is not called live.
LendingplannedNot determined.

`live` means a browser has done it against devnet and the chain was read back afterwards: 10 signatures, verified at slot 511,962,211. `planned` means nothing is written.

Built on

What it is built on

library or programversionrole
@solana-program/token-20220.20.0the Token-2022 confidential transfer instructions
@solana/zk-sdk0.5.4proof generation, as WASM from the Rust solana-zk-sdk
@solana/kit8.5.0rpc, transaction planning and compilation
@solana/web3.js1.99.0the wire format wallets speak, for signing only
TokenzQdBNbL…Token-2022the confidential transfer extension itself