Security model
What QuietPay protects, what it can't, and the contracts it relies on. QuietPay is experimental, unaudited software running on testnet.
What stays public, what doesn't
Visible to anyone on Robinhood Chain
- Your wallet address when you pay
- The amount
- The one-time receiving address
- When each transaction happened
Kept unlinkable by QuietPay
- Which main wallet a payment belongs to
- That two payments went to the same person
- Your receiving keys
- Which pool deposit a withdrawal came from
Where your keys live
- Each link's receiving keys
- Encrypted in this browser (AES-256-GCM). The key comes from a message your wallet signs and only lives in memory.
- The message signature
- Never stored. Re-signed each time you unlock.
- The key that moves a payment
- Worked out in your browser at claim time, used once to sign, then discarded.
- Backup files
- Encrypted with your passphrase (PBKDF2, 600,000 rounds). Keep the file and passphrase apart.
- Payment links
- Public keys only, kept after the # in the URL so they never reach a web server.
- Pool keys
- Derived in this browser from the same signature (separate derivation) and kept in the encrypted vault, so backups include them. Pool proofs are generated on this device.
No keys or secrets are ever sent to a server. QuietPay has no database or analytics. The only QuietPay server code is the pool relayer and approver, which receive finished proofs, never secrets.
Risks and how QuietPay handles them
Tampered or fake links
Every link is checked before you connect a wallet: checksum, network, accepted token, amount limits, expiry and valid keys. Links can't carry contract addresses or code. A link can still come from someone you don't trust, so only pay links from people you know.
Fake tokens or contracts
QuietPay only accepts one token per network and checks it onchain. The announcer must match QuietPay's exact compiled bytecode; anything else disables payments.
Losing your keys
Clearing browser data, private windows or a lost device lose the keys, and any unclaimed funds with them. Export an encrypted backup from the Receive page.
Phishing for your vault signature
Anyone who reads this browser's storage only sees ciphertext. Unlocking it needs your wallet's signature of QuietPay's vault message, so only sign that message on this site.
A compromised browser
Malware or a malicious extension running in the page can read keys while the vault is unlocked. QuietPay can't protect against that.
Network providers
Your browser talks to Robinhood Chain's RPC directly. It can see your IP address and which blocks you scan, never your keys. WalletConnect messages are end-to-end encrypted but pass through Reown's relay, which sees connection metadata.
Half-finished payments
Paying is two transactions: the transfer, then an announcement. If the announcement fails, only it can be retried; QuietPay will never resend a payment that was already sent. Payments count only after the transfer is verified onchain.
Gas for claims
When the QuietPay router is available, the payer includes a tiny amount of ETH with the payment, so you can move the funds without topping the address up from a wallet linked to you. QuietPay never funds addresses automatically.
Where you move the money
Moving a payment into your main wallet publicly links them, and the payer can follow it. Send to a fresh account or pay someone directly from the payment. Cashing out to an exchange account in your name links the funds to you.
The shielded pool
Pool withdrawals hide which deposit they came from, not that someone withdrew. Privacy depends on how many others use the pool, and matching amounts or quick withdrawals can still be connected. The pool contracts and circuits are 0xbow's audited Privacy Pools, unchanged, with their ceremony keys.
The relayer and approver
QuietPay runs a small relayer so withdrawals can go to an empty address. It sees your IP address and the withdrawal, can refuse to submit, but cannot change the recipient or fee because the proof fixes them. The approver publishes approvals by a public rule anyone can check. If either stops, deposits can always exit to their one-time address.
Reusable links
An any-amount link can be paid many times. Each payment still lands at its own address, and the public announcement carries no link ID, so observers cannot group payments to the same link. Everyone you share it with knows the payments go to you.
Contracts
The router moves a payment, the recipient's gas allowance and the announcement in one transaction, so they succeed or fail together. Like the announcer, it holds no funds and has no owner. The payer approves exactly the amount being paid.
Robinhood Chain Testnet (chain ID 46630)
- Payment token (test token, no value)
- 0x271C29c9d99e0DD4aE250c7dD302052355Cb3Db9
- ERC-5564 announcer
- 0x6Ec677c1195aC4951aFcAeAd14debaD6F74be577
- QuietPay router (one-transaction payments)
- 0xdc2B9cE56C2FCaC9a8324a519f6a7e97bC596193
- Shielded pool entrypoint (Privacy Pools by 0xbow)
- 0x81e32930B43A9F9b7528C33EeaF012a0c7A7Ceef
- Shielded pool
- 0x9d7c155C9572E9E233990DE9b417c7801FD66257
- Expected announcer bytecode hash
- 0x0af95fb5a29fc215ce3b805393c1f7c0530999f793faeb08f8bae6dd110797c0
Checked onchain just now
Announcer source codeSolidity 0.8.23, CC0, by ScopeLift
// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.23;
// Source: ScopeLift/stealth-address-erc-contracts (src/ERC5564Announcer.sol), CC0-1.0.
// Interface and logic are reproduced unchanged (only indentation differs) so it can be
// deployed on Robinhood Chain, where no verified ERC-5564 announcer deployment was found
// at the time of writing.
/// @notice `ERC5564Announcer` contract to emit an `Announcement` event to broadcast information
/// about a transaction involving a stealth address. See
/// [ERC-5564](https://eips.ethereum.org/EIPS/eip-5564) to learn more.
contract ERC5564Announcer {
/// @notice Emitted when something is sent to a stealth address.
/// @param schemeId Identifier corresponding to the applied stealth address scheme, e.g. 1 for
/// secp256k1, as specified in ERC-5564.
/// @param stealthAddress The computed stealth address for the recipient.
/// @param caller The caller of the `announce` function that emitted this event.
/// @param ephemeralPubKey Ephemeral public key used by the sender to derive the `stealthAddress`.
/// @param metadata Arbitrary data to emit with the event. The first byte MUST be the view tag.
/// @dev The remaining metadata can be used by the senders however they like. See
/// [ERC-5564](https://eips.ethereum.org/EIPS/eip-5564) for recommendations on how to structure
/// this metadata.
event Announcement(
uint256 indexed schemeId,
address indexed stealthAddress,
address indexed caller,
bytes ephemeralPubKey,
bytes metadata
);
/// @notice Called by integrators to emit an `Announcement` event.
/// @param schemeId Identifier corresponding to the applied stealth address scheme, e.g. 1 for
/// secp256k1, as specified in ERC-5564.
/// @param stealthAddress The computed stealth address for the recipient.
/// @param ephemeralPubKey Ephemeral public key used by the sender.
/// @param metadata Arbitrary data to emit with the event. The first byte MUST be the view tag.
/// @dev The remaining metadata can be used by the senders however they like. See
/// [ERC-5564](https://eips.ethereum.org/EIPS/eip-5564) for recommendations on how to structure
/// this metadata.
function announce(
uint256 schemeId,
address stealthAddress,
bytes memory ephemeralPubKey,
bytes memory metadata
) external {
emit Announcement(schemeId, stealthAddress, msg.sender, ephemeralPubKey, metadata);
}
}
The announcer only emits a public event. It holds no funds and has no owner. Payments go straight from the payer to the one-time address through the token contract.
The shielded pool uses 0xbow's Privacy Pools contracts and circuits (Apache-2.0), compiled unchanged with the audited compiler version. They were audited by Oxorio and Auditware. Before any deposit, your browser checks every pool contract against that build, and every circuit file against the trusted-setup ceremony output. Unlike the announcer and router, the pool has an owner: on testnet, QuietPay's deployer can upgrade the entrypoint, add pools and stop new deposits. Funds sit in the pool contract, which the owner cannot take from, and a depositor's exit back to its one-time address does not depend on the owner, the approver or the relayer.
Mainnet
Mainnet is switched off. It stays off until the announcer is deployed and verified on mainnet, USDG is confirmed onchain, the flow has been tested with real wallets on testnet, and the code has had an independent security review.