GRAIL
Privacy

Deposits and the standby

What a deposit does on chain, why new funds wait about an hour before they can be traded, and who controls that wait.

What a deposit is

A deposit is a Railgun shield. The browser builds one RelayAdapt transaction that wraps the ETH into WETH and shields it to the user's 0zk address:

RelayAdapt.multicall(true, [wrapBase(amount), shield([note])])

The connected wallet signs and pays gas. The chain shows that this wallet moved this amount into Railgun, and not which private address received it. Railgun's contracts deduct 0.25%, so a deposit of 0.002 ETH arrives as 0.001995 ETH.

Grail adds a 30% margin to the gas estimate. The gas a shield needs moves as Railgun's tree changes: we measured the minimum going from about 854,000 to about 856,900 within a few blocks. A wallet that used the exact estimate ran out of gas on our first mainnet test, and the funds stayed safely in the wallet.

Depositing before setup finishes

A shield needs only the recipient's public keys, a random value and the contract address. It does not need the tree. So Grail builds it from the SDK's note and contract classes without starting the engine, and people can deposit in the first seconds, even at 2% of the download. The deposit is recorded as soon as it is sent, so a reload does not hide it, and the record is removed if the chain reverts it.

The one-hour standby

This wait comes from Railgun's Private Proofs of Innocence (PPOI) system, which wallets on Railgun use to show that funds are not part of a dataset of flagged transactions, without revealing which funds are theirs. Railgun's documentation sets the standby at one hour, so that lists have time to update before new funds can move on.

The standby is automatic. No person at Railgun or Grail looks at a deposit, and neither can approve it or speed it up. Grail does not run a list or a POI node. The app asks a public POI node for the status and shows what it answers.

Measured on mainnetTime from deposit to spendable
Deposit of 0.003 ETH, with the tab closed for part of the wait62 minutes
Deposit of 0.0005 ETH, made at 2% of the first download61.5 minutes

The wait does not depend on the browser. People can leave and come back, and we tell them so on the deposit screen.

How the balance is shown

Railgun balance bucketShown in Grail as
SpendableAvailable
ShieldPending, MissingInternalPOI, MissingExternalPOI, ProofSubmittedOn its way, with a countdown after a deposit
ShieldBlockedA warning that the deposit did not pass, with a way to contact us

If a deposit does not pass

Railgun's documentation says that tokens can always be unshielded back to the original address, whatever their PPOI status. Grail's withdrawal form currently handles spendable funds only, so it does not offer that path yet. The recovery phrase still controls the funds, and we help anyone in this position directly.

Why it costs little privacy

Buying a few seconds after a fresh deposit of the same size would link the two by timing and amount, even with no standby. The wait pushes people away from the easiest mistake. The Grail interface treats it as a one-time step, and trades that follow do not repeat it.

Grail is an independent project built on Railgun's public contracts and SDK. Railgun contributors do not run, review or endorse Grail, and they did not write this documentation. Their own documentation is at docs.railgun.org.