QuietPay

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
QuietPay router (one-transaction payments)
0xdc2B9cE56C2FCaC9a8324a519f6a7e97bC596193
Shielded pool entrypoint (Privacy Pools by 0xbow)
0x81e32930B43A9F9b7528C33EeaF012a0c7A7Ceef
Expected announcer bytecode hash
0x0af95fb5a29fc215ce3b805393c1f7c0530999f793faeb08f8bae6dd110797c0

Checked onchain just now

Reading contracts from Robinhood Chain Testnet
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.