9b71b4c7 (main)
and
7d341501 (PR)
+14 -10
+14 -10
{
"adversaries": {
"promise": {
"protects": "recipient",
"text": "Hides which account a receiving address belongs to. The payer knows the address it was given; sender, asset, amount and where the funds go next are public."
},
"adversaries": [
{
"id": "publicObserver",
"label": "Public observer",
"description": "Everyone with a block explorer and some basic tools. Sees every public onchain event, but does no correlation beyond following links.",
"examples": "A curious counterparty, an employer, a journalist."
},
{
"id": "chainAnalyst",
"label": "Chain analyst",
"description": "Scrapes all public data and correlates it: timing, amounts, gas and wallet fingerprints, address clusters.",
"examples": "Chain analytics firms, ZachXBT, data brokers."
},
{
"id": "networkObserver",
"label": "Network observer",
"description": "Sits between the user and the services and sees traffic only: ISPs, VPNs, Tor exits, public RPCs and relayers. Learns IP addresses, timing, fingerprints and ciphertext. Services the operator runs count as the insider.",
"examples": "Infura or Alchemy, a Tornado relayer, a wallet vendor selling telemetry, Google captcha or analytics in the dapp frontend."
},
{
"id": "privilegedInsider",
"label": "Privileged insider",
"description": "Holds an operator role, custodies funds, receives keys or plaintext by design, or delivers the client: upgrade admin, custodian, view key holder, enclave operator, association set provider, hosted prover, registry, frontend host.",
"examples": "A compliance backdoor key, a DAO with an upgrade key, a KMS committee, an ASP operator, a custodial bridge."
},
{
"id": "futureAdversary",
"label": "Future adversary",
"description": "Harvest now, decrypt later. Holds every byte ever written onchain plus any retained logs, and breaks all public-key cryptography, by quantum computer or new mathematics: elliptic curves, pairings, RSA, lattices and isogenies. Hashes, Poseidon included, and symmetric ciphers survive.",
"description": "Harvest now, decrypt later. Holds every byte ever published and runs the known quantum attacks: elliptic curves, pairings and RSA fall. Hashes, symmetric ciphers and post-quantum schemes stand until an attack on them is known.",
"examples": "An intelligence agency archiving chain data today, then anyone once a break is public."
}
],
"fields": [
{
"id": "sender",
"label": "Sender",
"subject": "Sender",
"promiseLabel": "Sender privacy",
"description": "The Ethereum address that funds entered from, or that initiated a transfer."
},
{
"id": "recipient",
"label": "Recipient",
"subject": "Recipient",
"promiseLabel": "Recipient privacy",
"description": "Who receives the funds: the address they exit to, the receiver of a transfer, or whoever controls a one-time receiving address."
},
{
"id": "amount",
"label": "Amount",
"subject": "Amounts",
"promiseLabel": "Amount privacy",
"description": "The value moved."
},
{
"id": "asset",
"label": "Asset",
"subject": "Asset",
"promiseLabel": "Asset privacy",
"description": "Which token is moved."
},
{
"id": "linkage",
"label": "Link",
"subject": "Link",
"promiseLabel": "Link privacy",
"description": "Whether the entry and exit of the same funds, or sender and recipient of the same transfer, can be tied together."
}
],
"cells": {
"publicObserver": {
"sentiment": "good",
"exposureShort": "Each payment reaches a fresh address, and nothing onchain names the account behind it.",
"exposureContinued": "A send draws from several addresses in one transaction unless the user picks one with Advanced Control. Its change goes to a fresh address in the same transaction, which links the two.",
"advice": "Generate a fresh address for each receive, spend one address at a time with Advanced Control, and send to destinations with no public link to the user.",
"sources": [
{
"title": "Address derivation from server-held ephemeral material",
"url": "https://github.com/cloakedxyz/clkd-stealth/blob/9eb359efdd4ea31f5504bf81e57dcfe6f966dc14/src/shared/genStealthAddress.ts#L17-L58"
},
{
"title": "Input selection, Advanced Control and change",
"url": "https://clkd.xyz/docs/how-it-works#sending-funds"
},
{
"title": "A multi-address send links those addresses",
"url": "https://clkd.xyz/docs/how-it-works#what-is-visible-onchain"
}
],
"id": "publicObserver",
"value": "Recipient private",
"alsoExposed": []
},
"chainAnalyst": {
"sentiment": "warning",
"exposureShort": "Cloaked's relayers and fee Safe mark every spend, so an address hides only among Cloaked's users, a small set by onchain activity.",
"sentiment": "good",
"exposureShort": "Cloaked's relayers and fee Safe mark every spend as a Cloaked user's, so an address hides among all stealth addresses Cloaked has ever spent from.",
"exposureContinued": "Timing, distinctive amounts, recurring counterparties and change outputs cluster recipients further. Incognito withdrawals from Privacy Pools carry the same relayer and fee marks.",
"advice": "Space out related payments, avoid distinctive amounts and follow the user's own change outputs to see what a counterparty can trace.",
"sources": [
{
"title": "Documented links and change handling",
"url": "https://clkd.xyz/docs/how-it-works#what-is-visible-onchain"
},
{
"title": "Deterministic ephemeral keys stay offchain",
"url": "https://github.com/cloakedxyz/clkd-stealth/blob/9eb359efdd4ea31f5504bf81e57dcfe6f966dc14/src/shared/deriveDeterministicEphemeralKey.ts#L35-L68"
},
{
"title": "Fee Safe payers: 2,495 stealth addresses since launch, 1,148 in the 90 days to 2026-10-14",
"url": "https://etherscan.io/address/0x145444c66A32A0464059D400Dc488CCf4704f9B5#internaltx"
},
{
"title": "Relay fee receiver for Privacy Pools withdrawals",
"url": "https://api.clkd.xyz/relayer/details?chainId=1&assetAddress=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
}
],
"id": "chainAnalyst",
"value": "Recipient at risk",
"value": "Recipient private",
"alsoExposed": []
},
"networkObserver": {
"sentiment": "bad",
"exposureShort": "The app is closed source with no open alternative, so what it sends to third parties is up to Cloaked and can change at any time.",
"exposureContinued": "Today's app sends spends, quotes and balance reads to Cloaked's own API. Linking the user's own ENS name reads it through Alchemy under Cloaked's key, and wallet logins go through WalletConnect. A payer who looks up the user's name through a third-party RPC shows it that name and the new address.",
"sources": [
{
"title": "Service providers: RPC, hosting and wallet connection",
"url": "https://clkd.xyz/docs/privacy"
},
{
"contract": "OffchainResolver",
"title": "Name lookups return the signed answer through the payer's RPC"
}
],
"id": "networkObserver",
"value": "Recipient exposed",
"alsoExposed": []
},
"privilegedInsider": {
"sentiment": "bad",
"exposureShort": "Cloaked holds the viewing key, so it can regenerate every address and tie its activity to the user's account.",
"exposureContinued": "It also serves the closed-source app that handles the user's keys. Its relay submits both sides of every Incognito round trip through Privacy Pools and keeps the association.",
"sources": [
{
"title": "Viewing key and public spending key shared with the server",
"url": "https://github.com/cloakedxyz/clkd-stealth/blob/9eb359efdd4ea31f5504bf81e57dcfe6f966dc14/src/client/deriveServerBoundKeys.ts#L16-L53"
},
{
"title": "Privacy policy: retained pool associations and account data",
"url": "https://clkd.xyz/docs/privacy"
}
],
"id": "privilegedInsider",
"value": "Recipient exposed",
"alsoExposed": []
},
"futureAdversary": {
"sentiment": "warning",
"sentiment": "good",
"exposureShort": "No announcement is published, so address derivations cannot be replayed from the chain alone.",
"exposureContinued": "The viewing key held by Cloaked exposes the history regardless. Accounts created from a wallet signature reduce to that wallet's key plus a four-digit PIN. Passkey secrets do not follow from breaking the passkey.",
"advice": "Create the user's account with a passkey, not from a wallet signature. Treat the address history shared with Cloaked as permanently disclosed.",
"exposureContinued": "Accounts created from a wallet signature reduce to that wallet's key plus a four-digit PIN. Passkey secrets do not follow from breaking the passkey.",
"advice": "Create the user's account with a passkey, not from a wallet signature. Keep the backup file from setup, since the passkey works only on Cloaked's domain.",
"sources": [
{
"title": "Stealth signing keys mix the spending key with a hashed secret",
"url": "https://github.com/cloakedxyz/clkd-stealth/blob/9eb359efdd4ea31f5504bf81e57dcfe6f966dc14/src/client/genStealthPrivateKey.ts#L17-L34"
},
{
"title": "Four-digit PIN and wallet address determine the signed message",
"url": "https://github.com/cloakedxyz/clkd-stealth/blob/9eb359efdd4ea31f5504bf81e57dcfe6f966dc14/src/client/genCloakedMessage.ts#L15-L48"
},
{
"title": "Independent secrets, including two WebAuthn PRF outputs",
"url": "https://github.com/cloakedxyz/clkd-stealth/blob/9eb359efdd4ea31f5504bf81e57dcfe6f966dc14/src/client/genKeys.ts#L7-L67"
},
{
"title": "Operator data and retention",
"url": "https://clkd.xyz/docs/privacy"
}
],
"id": "futureAdversary",
"value": "Recipient at risk",
"value": "Recipient private",
"alsoExposed": []
}
}
},
"anonymitySet": {
"type": "not-applicable",
"description": "Cloaked sends funds to one-time stealth addresses instead of mixing deposits in a shared pool."
},
"attributes": [
{
"id": "stealthAddresses",
"label": "Stealth addresses",
"description": "Uses fresh, one-time recipient addresses to obscure who controls the receiving address."
},
{
"id": "anyAmount",
"label": "Any amount",
"description": "Deposits and withdrawals can have any size."
}
],
"category": {
"id": "stealthAddress",
"label": "Stealth address",
"description": "Payments land on fresh one-time addresses. Hides which recipient a payment is for."
},
"exitWindow": {
"value": "Infinite",
"sentiment": "good",
"orderHint": 9007199254740991,
"description": "Balances sit in addresses the user's keys control, and the open recovery tool exports their keys. Cloaked can spend them only with the user's key material.",
"description": "Balances sit in addresses the user's keys control, and the open recovery tool exports their keys from the wallet and PIN or from the backup file saved at setup. Cloaked can spend them only with the user's key material.",
"walkawayTest": {
"passed": false,
"reason": "New payment-address generation, ENS resolution, address indexing, transaction construction, and relaying depend on the hosted Cloaked service."
}
},
"reproducibility": {
"value": "Partially reproducible",
"sentiment": "warning",
"description": "The web app and the browser extension are closed source. The open stealth library and recovery tool derive keys and recover funds without Cloaked. The API, ENS gateway, indexer and relay are closed."
},
"riskSummary": "## Funds can be stolen if\n1. the closed-source app is malicious or compromised and exfiltrates spending keys.\n2. the accepted ENS signer returns an attacker-controlled payment address for a Cloaked name.\n
\n## Funds can be lost if\n1. a user loses the passkey and encrypted backup, or the wallet and PIN, needed to re-derive the spending key.\n2. the service and the app derive different address data and a payment reaches an address whose key the user cannot recreate.\n
\n## Privacy can be lost if\n1. Cloaked, or anyone who obtains its records now or later, uses the viewing keys to link every account's addresses (see privileged insider and future adversary).\n2. Cloaked's relayers and fee Safe mark every spend, so an address hides only among Cloaked's few users (see chain analyst).\n3. Cloaked changes its closed-source app to send account data to third parties, which users cannot check (see network observer).\n4. a user relies on the Incognito balance, whose relay keeps the link between deposit and withdrawal (see privileged insider).",
"riskSummary": "## Funds can be stolen if\n1. the closed-source app is malicious or compromised and exfiltrates spending keys.\n2. the accepted ENS signer returns an attacker-controlled payment address for a Cloaked name.\n
\n## Funds can be lost if\n1. a user loses the passkey and encrypted backup, or the wallet and PIN, needed to re-derive the spending key.\n2. the service and the app derive different address data and a payment reaches an address whose key the user cannot recreate.\n
\n## Privacy can be lost if\n1. Cloaked, or anyone who obtains its records now or later, uses the viewing keys to link every account's addresses (see privileged insider).\n2. Cloaked's relayers and fee Safe mark every spend as a Cloaked user's (see chain analyst).\n3. Cloaked changes its closed-source app to send account data to third parties, which users cannot check (see network observer).\n4. a user relies on the Incognito balance, whose relay keeps the link between deposit and withdrawal (see privileged insider).",
"tokens": [],
"trackedOn": [
"ethereum"
],
"upgradesAndGovernance": {
"content": "Cloaked changes its hosted app, API, ENS gateway, indexer and relay at will, without notice onchain.\n\nThe OffchainResolver is immutable. Its owner can replace the gateway URLs and the accepted signer instantly, and the signer can authenticate any answer, including a payment address. Owner and signer are the same EOA. This affects new lookups only, since existing addresses stay under their owners' keys."
}
}
+6 -6
+6 -6
{
"adversaries": {
"promise": {
"protects": "recipient",
"text": "Hides which account a receiving Safe belongs to. The payer knows the address it was given; sender, asset, amount and where the funds go next are public."
},
"adversaries": [
{
"id": "publicObserver",
"label": "Public observer",
"description": "Everyone with a block explorer and some basic tools. Sees every public onchain event, but does no correlation beyond following links.",
"examples": "A curious counterparty, an employer, a journalist."
},
{
"id": "chainAnalyst",
"label": "Chain analyst",
"description": "Scrapes all public data and correlates it: timing, amounts, gas and wallet fingerprints, address clusters.",
"examples": "Chain analytics firms, ZachXBT, data brokers."
},
{
"id": "networkObserver",
"label": "Network observer",
"description": "Sits between the user and the services and sees traffic only: ISPs, VPNs, Tor exits, public RPCs and relayers. Learns IP addresses, timing, fingerprints and ciphertext. Services the operator runs count as the insider.",
"examples": "Infura or Alchemy, a Tornado relayer, a wallet vendor selling telemetry, Google captcha or analytics in the dapp frontend."
},
{
"id": "privilegedInsider",
"label": "Privileged insider",
"description": "Holds an operator role, custodies funds, receives keys or plaintext by design, or delivers the client: upgrade admin, custodian, view key holder, enclave operator, association set provider, hosted prover, registry, frontend host.",
"examples": "A compliance backdoor key, a DAO with an upgrade key, a KMS committee, an ASP operator, a custodial bridge."
},
{
"id": "futureAdversary",
"label": "Future adversary",
"description": "Harvest now, decrypt later. Holds every byte ever written onchain plus any retained logs, and breaks all public-key cryptography, by quantum computer or new mathematics: elliptic curves, pairings, RSA, lattices and isogenies. Hashes, Poseidon included, and symmetric ciphers survive.",
"description": "Harvest now, decrypt later. Holds every byte ever published and runs the known quantum attacks: elliptic curves, pairings and RSA fall. Hashes, symmetric ciphers and post-quantum schemes stand until an attack on them is known.",
"examples": "An intelligence agency archiving chain data today, then anyone once a break is public."
}
],
"fields": [
{
"id": "sender",
"label": "Sender",
"subject": "Sender",
"promiseLabel": "Sender privacy",
"description": "The Ethereum address that funds entered from, or that initiated a transfer."
},
{
"id": "recipient",
"label": "Recipient",
"subject": "Recipient",
"promiseLabel": "Recipient privacy",
"description": "Who receives the funds: the address they exit to, the receiver of a transfer, or whoever controls a one-time receiving address."
},
{
"id": "amount",
"label": "Amount",
"subject": "Amounts",
"promiseLabel": "Amount privacy",
"description": "The value moved."
},
{
"id": "asset",
"label": "Asset",
"subject": "Asset",
"promiseLabel": "Asset privacy",
"description": "Which token is moved."
},
{
"id": "linkage",
"label": "Link",
"subject": "Link",
"promiseLabel": "Link privacy",
"description": "Whether the entry and exit of the same funds, or sender and recipient of the same transfer, can be tied together."
}
],
"cells": {
"publicObserver": {
"sentiment": "good",
"exposureShort": "Each payment reaches a fresh Safe, and nothing onchain names the account behind it.",
"exposureContinued": "A send that draws from several of the user's Safes shows onchain that they belong together.",
"advice": "Generate a fresh address for each receive, label payments by payer and send from one label at a time, and send to destinations with no public link to the user.",
"sources": [
{
"title": "Counterfactual receiving Safe and one-time stealth signer",
"url": "https://docs.fluidkey.com/technical-documentation/technical-walkthrough/#3-stealth-accounts"
},
{
"title": "Safe owner and initialization data determine the address",
"url": "https://github.com/fluidkey/fluidkey-stealth-account-kit/blob/2a4ccfafef127165c11ba16fc16235c919698ec2/src/predictStealthSafeAddress.ts#L32-L104"
},
{
"title": "Labels limit which Safes fund a send",
"url": "https://docs.fluidkey.com/readme/labels/"
}
],
"id": "publicObserver",
"value": "Recipient private",
"alsoExposed": []
},
"chainAnalyst": {
"sentiment": "good",
"exposureShort": "At least 2,189 accounts have claimed Fluidkey's 'score' token, giving a lower bound of the anonymity set.",
"exposureContinued": "A Safe looks like any new address until Fluidkey's relayer spends from it or deposits its funds for auto-earn. A claimed score sits on its own stealth address that holds nothing else, and its amount grows partly with the account's balance.",
"advice": "Ask for a new address for each payment, also when it arrives on another chain.",
"sources": [
{
"contract": "FluidkeyScore",
"title": "Score holders, one address per claiming account"
},
{
"title": "Score claimed in the app, based partly on total balance",
"url": "https://docs.fluidkey.com/readme/score/"
},
{
"title": "The score accrues on a stealth address that holds nothing else",
"url": "https://www.fluidkey.com/blog/fluidkey-score"
},
{
"contract": "SmartAccountRelayer",
"title": "Fluidkey's relayer contract submits every send and auto-earn deposit"
},
{
"title": "Auto-earn setup records the Safe that installs it",
"url": "https://github.com/fluidkey/fluidkey-earn-module/blob/122cde19940d06b94c0027f4cd2e22e7fa19129a/src/FluidkeyEarnModule.sol#L243-L260"
},
{
"title": "Shared derivation path permits the same address on several chains",
"url": "https://docs.fluidkey.com/technical-documentation/technical-walkthrough/#3a-stealth-signer-derivation"
}
],
"id": "chainAnalyst",
"value": "Recipient private",
"alsoExposed": []
},
"networkObserver": {
"sentiment": "bad",
"exposureShort": "The app is closed source with no open alternative, so what it sends to third parties is up to Fluidkey and can change at any time.",
"exposureContinued": "Today, the web app reads the chain only through Fluidkey's servers and gives outside services just the user's login and username. A payer who looks up the user's name through a third-party RPC shows it that name and the new address.",
"sources": [
{
"title": "The app's content security policy lists every endpoint it contacts",
"url": "https://app.fluidkey.com"
},
{
"contract": "OffchainResolver",
"title": "Name lookups return the signed answer through the payer's RPC"
}
],
"id": "networkObserver",
"value": "Recipient exposed",
"alsoExposed": []
},
"privilegedInsider": {
"sentiment": "bad",
"exposureShort": "Fluidkey holds the viewing key, so it can regenerate every address and tie its activity to the user's account.",
"exposureContinued": "It also runs the closed-source app that handles the user's keys. With Google or Apple login on the web, Privy's code creates the signature the user's keys come from. Bank transfers add the user's verified identity, and Hide Trail shows the user's route to Houdini and two exchanges.",
"sources": [
{
"title": "Private viewing key shared with the service",
"url": "https://github.com/fluidkey/fluidkey-stealth-account-kit/blob/2a4ccfafef127165c11ba16fc16235c919698ec2/src/extractViewingPrivateKeyNode.ts#L14-L30"
},
{
"title": "Web keys are generated through a Privy embedded wallet",
"url": "https://docs.fluidkey.com/readme/account-set-up/"
},
{
"title": "Verification results and identity attributes",
"url": "https://www.fluidkey.com/privacy"
},
{
"title": "Hide Trail and its exchange intermediaries",
"url": "https://docs.fluidkey.com/readme/advanced-privacy/"
}
],
"id": "privilegedInsider",
"value": "Recipient exposed",
"alsoExposed": []
},
"futureAdversary": {
"sentiment": "warning",
"sentiment": "good",
"exposureShort": "No announcement is published, so address derivations cannot be replayed from the chain alone.",
"exposureContinued": "The viewing key held by Fluidkey exposes the history regardless. Accounts created from a wallet signature reduce to that wallet's key plus a four-digit PIN.",
"advice": "Create the user's account in the mobile app, with Google or Apple login, or with a new wallet that has never sent a transaction. Treat the viewing key shared with Fluidkey as permanently disclosed.",
"exposureContinued": "Accounts created from a wallet signature reduce to that wallet's key plus a four-digit PIN.",
"advice": "Connect a new wallet that has never sent a transaction instead of logging in with Google or Apple.",
"sources": [
{
"title": "Stealth signer depends on a hashed shared secret",
"url": "https://github.com/fluidkey/fluidkey-stealth-account-kit/blob/2a4ccfafef127165c11ba16fc16235c919698ec2/src/generateStealthPrivateKey.ts#L11-L21"
},
{
"title": "Signature halves generate the viewing and spending keys",
"url": "https://github.com/fluidkey/fluidkey-stealth-account-kit/blob/2a4ccfafef127165c11ba16fc16235c919698ec2/src/generateKeysFromSignature.ts#L11-L36"
},
{
"title": "Wallet address and PIN determine the key-generation message",
"url": "https://github.com/fluidkey/fluidkey-stealth-account-kit/blob/2a4ccfafef127165c11ba16fc16235c919698ec2/src/utils/generateFluidkeyMessage.ts#L10-L32"
},
{
"title": "Recovery supports a four-digit PIN, defaulting to 0000",
"url": "https://github.com/fluidkey/sara/blob/e6e4fcd9e718722948b82fa0e819e0c4fca46e0d/src/components/GenerateKeysJourneyStep.tsx#L28-L90"
}
],
"id": "futureAdversary",
"value": "Recipient at risk",
"value": "Recipient private",
"alsoExposed": []
}
}
},
"anonymitySet": {
"type": "not-applicable",
"description": "Fluidkey sends funds to individual stealth Safes instead of mixing deposits in a shared pool."
},
"attributes": [
{
"id": "stealthAddresses",
"label": "Stealth addresses",
"description": "Uses fresh, one-time recipient addresses to obscure who controls the receiving address."
},
{
"id": "anyAmount",
"label": "Any amount",
"description": "Deposits and withdrawals can have any size."
},
{
"id": "defi",
"label": "DeFi",
"description": "Interop with DeFi vaults through stealth Safes."
}
],
"category": {
"id": "stealthAddress",
"label": "Stealth address",
"description": "Payments land on fresh one-time addresses. Hides which recipient a payment is for."
},
"exitWindow": {
"value": "Infinite",
"sentiment": "good",
"orderHint": 9007199254740991,
"description": "The user's funds sit in Safes controlled only by their keys. The open recovery app finds and withdraws them without Fluidkey. Money in auto-earn vaults follows the vaults' withdrawal rules.",
"walkawayTest": {
"passed": false,
"reason": "Name lookups, new addresses in the app, finding the user's Safes and submitting sends all run on Fluidkey's servers."
}
},
"reproducibility": {
"value": "Partially reproducible",
"sentiment": "warning",
"description": "The web and mobile apps are closed source. The open stealth account kit and recovery app derive keys, verify addresses and recover funds without Fluidkey. The API, ENS gateway, indexer and relayer are closed."
},
"riskSummary": "## Funds can be stolen if\n1. the closed-source app is malicious or hacked and steals the user's spending keys.\n2. Privy's code or key share is compromised, for accounts created with Google or Apple login on the web.\n3. a Fluidkey signer returns an attacker's address when a payer looks up a Fluidkey name.\n4. Fluidkey's server marks a transfer as approved, and the open app signs it without showing the user.\n
\n## Funds can be lost if\n1. a user loses the login, wallet, PIN or backup needed to recover the spending key.\n2. Fluidkey's server gives out a wrong address, for example one built with a different Safe setup, and the user's keys cannot withdraw from it.\n3. an auto-earn vault loses funds or blocks withdrawals, or a service used by Hide Trail keeps the funds.\n
\n## Privacy can be lost if\n1. Fluidkey, or anyone who obtains its records, uses the viewing keys to link all Safes of every account (see privileged insider and future adversary).\n2. Fluidkey changes its closed-source app to send account data to outside services, which users cannot check (see network observer).\n3. a user takes Hide Trail and Houdini or the exchanges link the route from their records (see privileged insider).",
"riskSummary": "## Funds can be stolen if\n1. the closed-source app is malicious or hacked and steals the user's spending keys.\n2. Privy's code or key share is compromised, for accounts created with Google or Apple login on the web.\n3. a Fluidkey signer returns an attacker's address when a payer looks up a Fluidkey name.\n4. Fluidkey's server marks a transfer as approved, and the open app signs it without showing the user.\n
\n## Funds can be lost if\n1. a user loses the login, wallet, PIN or backup needed to recover the spending key.\n2. Fluidkey's server gives out a wrong address, for example one built with a different Safe setup, and the user's keys cannot withdraw from it.\n3. an auto-earn vault loses funds or blocks withdrawals, or a service used by Hide Trail keeps the funds.\n
\n## Privacy can be lost if\n1. Fluidkey, or anyone who obtains its records, uses the viewing keys to link all Safes of every account (see privileged insider).\n2. Fluidkey changes its closed-source app to send account data to outside services, which users cannot check (see network observer).\n3. a user takes Hide Trail and Houdini or the exchanges link the route from their records (see privileged insider).\n4. Fluidkey's relayer marks every spend as a Fluidkey account's (see chain analyst).",
"tokens": [],
"trackedOn": [
"ethereum",
"base",
"arbitrum",
"optimism",
"polygonpos",
"gnosis"
],
"upgradesAndGovernance": {
"content": "Fluidkey changes its app, API, name gateway, indexer and relayer at will, without notice onchain.\n\nThe OffchainResolver is immutable. Its owner, the Fluidkey Resolver Multisig, can instantly change where name lookups are answered and which keys may sign the answers. A signer can return any address for a name. This affects new lookups only, since existing Safes stay under their owners' keys.\n\nThe Fluidkey Earn module is immutable on each chain. Its owner, the Fluidkey Earn Owner multisig, publishes vault sets and chooses the relayers, which can also add or remove other relayers. An existing Safe moves to a new vault set only by its own call."
}
}
+1 -1
+1 -1
{
"adversaries": {
"promise": {
"protects": "linkage",
"text": "Hides which funds leaving Ethereum come back as which, by passing them through Monero between two custodial swaps. Both Ethereum legs are public."
},
"adversaries": [
{
"id": "publicObserver",
"label": "Public observer",
"description": "Everyone with a block explorer and some basic tools. Sees every public onchain event, but does no correlation beyond following links.",
"examples": "A curious counterparty, an employer, a journalist."
},
{
"id": "chainAnalyst",
"label": "Chain analyst",
"description": "Scrapes all public data and correlates it: timing, amounts, gas and wallet fingerprints, address clusters.",
"examples": "Chain analytics firms, ZachXBT, data brokers."
},
{
"id": "networkObserver",
"label": "Network observer",
"description": "Sits between the user and the services and sees traffic only: ISPs, VPNs, Tor exits, public RPCs and relayers. Learns IP addresses, timing, fingerprints and ciphertext. Services the operator runs count as the insider.",
"examples": "Infura or Alchemy, a Tornado relayer, a wallet vendor selling telemetry, Google captcha or analytics in the dapp frontend."
},
{
"id": "privilegedInsider",
"label": "Privileged insider",
"description": "Holds an operator role, custodies funds, receives keys or plaintext by design, or delivers the client: upgrade admin, custodian, view key holder, enclave operator, association set provider, hosted prover, registry, frontend host.",
"examples": "A compliance backdoor key, a DAO with an upgrade key, a KMS committee, an ASP operator, a custodial bridge."
},
{
"id": "futureAdversary",
"label": "Future adversary",
"description": "Harvest now, decrypt later. Holds every byte ever written onchain plus any retained logs, and breaks all public-key cryptography, by quantum computer or new mathematics: elliptic curves, pairings, RSA, lattices and isogenies. Hashes, Poseidon included, and symmetric ciphers survive.",
"description": "Harvest now, decrypt later. Holds every byte ever published and runs the known quantum attacks: elliptic curves, pairings and RSA fall. Hashes, symmetric ciphers and post-quantum schemes stand until an attack on them is known.",
"examples": "An intelligence agency archiving chain data today, then anyone once a break is public."
}
],
"fields": [
{
"id": "sender",
"label": "Sender",
"subject": "Sender",
"promiseLabel": "Sender privacy",
"description": "The Ethereum address that funds entered from, or that initiated a transfer."
},
{
"id": "recipient",
"label": "Recipient",
"subject": "Recipient",
"promiseLabel": "Recipient privacy",
"description": "Who receives the funds: the address they exit to, the receiver of a transfer, or whoever controls a one-time receiving address."
},
{
"id": "amount",
"label": "Amount",
"subject": "Amounts",
"promiseLabel": "Amount privacy",
"description": "The value moved."
},
{
"id": "asset",
"label": "Asset",
"subject": "Asset",
"promiseLabel": "Asset privacy",
"description": "Which token is moved."
},
{
"id": "linkage",
"label": "Link",
"subject": "Link",
"promiseLabel": "Link privacy",
"description": "Whether the entry and exit of the same funds, or sender and recipient of the same transfer, can be tied together."
}
],
"cells": {
"publicObserver": {
"sentiment": "good",
"exposureShort": "The Monero transactions between the deposit into a swap service and the payout from its hot wallet hide sender, recipient and amount.",
"exposureContinued": "Both Ethereum transfers show address, token and amount.",
"advice": "Exit to a new in-app Ethereum wallet made with Create New Recovery Phrase.",
"interior": {
"sender": "private",
"recipient": "private",
"amount": "private",
"asset": {
"verdict": "exposed",
"note": "Only XMR exists inside. The source asset is public on Ethereum."
},
"linkage": {
"verdict": "atRisk",
"note": "An EVM wallet in Cake has one address, so exiting to the wallet that deposited pays the address that deposited."
}
},
"sources": [
{
"title": "The deposit is a plain transfer from the wallet to the address the service returned",
"url": "https://github.com/cake-tech/cake_wallet/blob/7ce3cd75c3fd0c0add1cead41038ab8806ffebde/lib/view_model/exchange/exchange_trade_view_model.dart#L200-L206"
},
{
"title": "An EVM wallet has a single address",
"url": "https://github.com/cake-tech/cake_wallet/blob/7ce3cd75c3fd0c0add1cead41038ab8806ffebde/cw_evm/lib/evm_chain_wallet_addresses.dart#L11-L38"
},
{
"title": "Every input names 16 ring members",
"url": "https://github.com/monero-project/monero/blob/v0.18.5.1/src/cryptonote_core/blockchain.cpp#L3268"
},
{
"title": "Amounts are encrypted to the recipient",
"url": "https://github.com/monero-project/monero/blob/v0.18.5.1/src/ringct/rctOps.cpp#L672-L720"
}
],
"id": "publicObserver",
"value": "Link private",
"alsoExposed": []
},
"chainAnalyst": {
"sentiment": "good",
"exposureShort": "Only amount and timing can pair a deposit into a swap service with a payout from a hot wallet serving every asset the service trades.",
"advice": "Withdraw common amounts rather than everything at once. Wait before exiting and pick a different time of day than the deposit. Exit to a fresh address every time and spend from it with a different wallet than the one that deposited.",
"interior": {
"sender": "private",
"recipient": "private",
"amount": "private",
"asset": "exposed",
"linkage": {
"verdict": "atRisk",
"note": "A round trip of similar amount and timing pairs the two Ethereum legs."
}
},
"id": "chainAnalyst",
"value": "Link private",
"alsoExposed": []
},
"networkObserver": {
"sentiment": "warning",
"exposureShort": "Built-in Tor sends every call over one shared circuit for up to ten minutes, so only separate app sessions keep the legs apart.",
"exposureContinued": "Moralis receives every Ethereum wallet the app opens, so deposit and exit wallets kept in the app pair up whenever both open close together.",
"advice": "Turn on built-in Tor and restart the app, since the Ethereum client keeps the connection it started with. After the entry, delete the deposit wallet from Cake and restart, so later sessions only see the exit wallet.",
"interior": {
"sender": "private",
"recipient": "private",
"amount": "private",
"asset": "exposed",
"linkage": {
"verdict": "atRisk",
"note": "Private only over built-in Tor, with each leg in its own app session."
}
},
"sources": [
{
"title": "Built-in Tor is off unless the user enables it",
"url": "https://github.com/cake-tech/cake_wallet/blob/7ce3cd75c3fd0c0add1cead41038ab8806ffebde/lib/store/settings_store.dart#L1590"
},
{
"title": "Opening a wallet connects its node and sends its address to Moralis",
"url": "https://github.com/cake-tech/cake_wallet/blob/7ce3cd75c3fd0c0add1cead41038ab8806ffebde/lib/reactions/on_current_wallet_change.dart#L94-L113"
},
{
"title": "Embedded Tor config: one SocksPort, no isolation flags",
"url": "https://github.com/cake-tech/cake_wallet/blob/7ce3cd75c3fd0c0add1cead41038ab8806ffebde/cw_core/lib/utils/tor/torch.dart#L65-L70"
},
{
"title": "The Ethereum client binds its proxy setting once",
"url": "https://github.com/cake-tech/cake_wallet/blob/7ce3cd75c3fd0c0add1cead41038ab8806ffebde/cw_evm/lib/clients/evm_chain_client.dart#L24"
}
],
"id": "networkObserver",
"value": "Link at risk",
"alsoExposed": []
},
"privilegedInsider": {
"sentiment": "bad",
"exposureShort": "Each swap service custodies its leg and can hold the funds until the user passes identity checks, and identities on both legs link them.",
"exposureContinued": "The entry service knows the XMR output it paid the user, and the exit service sees the rings of the transaction that pays it. Together they find that output in the rings behind the exit, and self-transfers only widen the search.",
"interior": {
"sender": {
"verdict": "atRisk",
"note": "Rings that reference the service's payout output point to the spend of the user's XMR."
},
"recipient": "private",
"amount": "private",
"asset": "exposed",
"linkage": {
"verdict": "atRisk",
"note": "A service can hold either leg until the user provides identification."
}
},
"sources": [
{
"title": "Breaking Monero: poisoned outputs, the attack by a counterparty on both sides",
"url": "https://www.monerooutreach.org/breaking-monero/poisoned-outputs.html"
},
{
"title": "ChangeNOW: automated AML holds, KYC through SumSub, refund minus fees",
"url": "https://changenow.io/faq/kyc-aml"
}
],
"id": "privilegedInsider",
"value": "Link exposed",
"alsoExposed": [
{
"field": "sender",
"exposure": "atRisk"
}
]
},
"futureAdversary": {
"sentiment": "bad",
"exposureShort": "Whoever breaks elliptic-curve cryptography recovers every Monero output key from public chain data, so every ring shows its real spend.",
"exposureContinued": "A known address also yields its view key, and anyone learns a service's address by starting a trade. The user's XMR can then be followed from the entry service to the exit service, where amounts and timing pair it with both Ethereum legs.",
"interior": {
"sender": "exposed",
"recipient": {
"verdict": "atRisk",
"note": "Readable for outputs to known addresses, and the services know the user's address."
},
"amount": {
"verdict": "atRisk",
"note": "Readable for outputs to known addresses."
},
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "A key image is the output key hashed to a point times its private key",
"url": "https://github.com/monero-project/monero/blob/v0.18.5.1/src/crypto/crypto.cpp#L621-L628"
},
{
"title": "Zero to Monero: one-time addresses, amount encryption and key images (chapters 4 to 6)",
"url": "https://www.getmonero.org/library/Zero-to-Monero-2-0-0.pdf"
}
],
"id": "futureAdversary",
"value": "Link exposed",
"alsoExposed": [
{
"field": "sender",
"exposure": "exposed"
},
{
"field": "recipient",
"exposure": "atRisk"
},
{
"field": "amount",
"exposure": "atRisk"
}
]
}
}
},
"anonymitySet": {
"type": "not-applicable",
"description": "Each Monero spend hides among the 16 members of its ring, and each self-transfer multiplies the candidates by about 30."
},
"attributes": [
{
"id": "bridged",
"label": "Bridged",
"description": "Funds leave Ethereum through a bridge and gain their privacy on another chain."
},
{
"id": "transfers",
"label": "Transfers",
"description": "Private transfers within the shielded pool."
},
{
"id": "anyAmount",
"label": "Any amount",
"description": "Deposits and withdrawals can have any size."
}
],
"category": {
"id": "shieldedLedger",
"label": "Shielded ledger",
"description": "A pool with transfers or DeFi inside. Hides who pays whom and which deposit became which withdrawal."
},
"exitWindow": {
"value": "None",
"sentiment": "bad",
"orderHint": 0,
"description": "Funds in transit sit with the swap service, which can steal them.",
"walkawayTest": {
"passed": false,
"reason": "Deposit and payout both depend on the swap service. If it stops, funds in transit are lost or refunded at its discretion."
}
},
"reproducibility": {
"value": "Partially reproducible",
"sentiment": "warning",
"description": "Cake Wallet and Monero are open source. The swap services run closed systems."
},
"riskSummary": "## Funds can be stolen if\n1. a swap service does not pay out.\n2. a service's hot wallet is compromised during the trade.\n
\n## Funds can be frozen if\n1. a service holds the deposit pending identity verification.\n2. a service refunds minus fees and blacklists the deposit address.\n
\n## Privacy can be lost if\n1. a service holds a leg until the user identifies, since identities on both legs link them (see privileged insider).\n2. one party sees both legs, like one service used twice, and finds its payout in the rings behind the exit (see privileged insider).\n3. swap services, Blink, Etherscan, Moralis, the RPC and the Monero node see the user's IP, since Tor is off by default (see network observer).\n4. elliptic-curve cryptography is broken, which reveals the real spend in every ring (see future adversary).",
"tokens": [],
"trackedOn": [
"ethereum"
],
"upgradesAndGovernance": {
"content": "Three parties change this swap route, each instantly and offchain since there are no onchain contracts.\n\n### Cake Labs LLC (the wallet)\n\nCake picks the swap services, their defaults and its API keys with each app release. Cake Wallet is MIT-licensed and self-custodial.\n\n### The swap services (the custodians)\n\nEach service sets its own terms, limits and compliance rules and can change them at any time.\n\n### Monero (the chain)\n\nRules change through scheduled hard forks. The mainnet table ends at version 16, active since block 2,689,608 (August 2022), with a ring size of 16."
}
}
+5 -15
+5 -15
{
"adversaries": {
"promise": {
"protects": "linkage",
"text": "Hides note amounts and owners. Which notes fund which, and every deposit and withdrawal, are public."
},
"adversaries": [
{
"id": "publicObserver",
"label": "Public observer",
"description": "Everyone with a block explorer and some basic tools. Sees every public onchain event, but does no correlation beyond following links.",
"examples": "A curious counterparty, an employer, a journalist."
},
{
"id": "chainAnalyst",
"label": "Chain analyst",
"description": "Scrapes all public data and correlates it: timing, amounts, gas and wallet fingerprints, address clusters.",
"examples": "Chain analytics firms, ZachXBT, data brokers."
},
{
"id": "networkObserver",
"label": "Network observer",
"description": "Sits between the user and the services and sees traffic only: ISPs, VPNs, Tor exits, public RPCs and relayers. Learns IP addresses, timing, fingerprints and ciphertext. Services the operator runs count as the insider.",
"examples": "Infura or Alchemy, a Tornado relayer, a wallet vendor selling telemetry, Google captcha or analytics in the dapp frontend."
},
{
"id": "privilegedInsider",
"label": "Privileged insider",
"description": "Holds an operator role, custodies funds, receives keys or plaintext by design, or delivers the client: upgrade admin, custodian, view key holder, enclave operator, association set provider, hosted prover, registry, frontend host.",
"examples": "A compliance backdoor key, a DAO with an upgrade key, a KMS committee, an ASP operator, a custodial bridge."
},
{
"id": "futureAdversary",
"label": "Future adversary",
"description": "Harvest now, decrypt later. Holds every byte ever written onchain plus any retained logs, and breaks all public-key cryptography, by quantum computer or new mathematics: elliptic curves, pairings, RSA, lattices and isogenies. Hashes, Poseidon included, and symmetric ciphers survive.",
"description": "Harvest now, decrypt later. Holds every byte ever published and runs the known quantum attacks: elliptic curves, pairings and RSA fall. Hashes, symmetric ciphers and post-quantum schemes stand until an attack on them is known.",
"examples": "An intelligence agency archiving chain data today, then anyone once a break is public."
}
],
"fields": [
{
"id": "sender",
"label": "Sender",
"subject": "Sender",
"promiseLabel": "Sender privacy",
"description": "The Ethereum address that funds entered from, or that initiated a transfer."
},
{
"id": "recipient",
"label": "Recipient",
"subject": "Recipient",
"promiseLabel": "Recipient privacy",
"description": "Who receives the funds: the address they exit to, the receiver of a transfer, or whoever controls a one-time receiving address."
},
{
"id": "amount",
"label": "Amount",
"subject": "Amounts",
"promiseLabel": "Amount privacy",
"description": "The value moved."
},
{
"id": "asset",
"label": "Asset",
"subject": "Asset",
"promiseLabel": "Asset privacy",
"description": "Which token is moved."
},
{
"id": "linkage",
"label": "Link",
"subject": "Link",
"promiseLabel": "Link privacy",
"description": "Whether the entry and exit of the same funds, or sender and recipient of the same transfer, can be tied together."
}
],
"cells": {
"publicObserver": {
"sentiment": "bad",
"exposureShort": "Every transaction names the notes it spends and creates, so which notes fund which is public.",
"exposureContinued": "Empty padding notes have a zero commitment, so single-input and single-output transactions are recognizable. Each deposit or withdrawal shows address and amount and points at one node of that graph. The per-transaction proofs use a flavor its authors document as not zero-knowledge, and how much of a note it leaks is not established.",
"interior": {
"sender": {
"verdict": "private",
"note": "The owner key is hidden, but the spent note is a public graph node."
},
"recipient": {
"verdict": "private",
"note": "Recipient and change outputs are indistinguishable."
},
"amount": {
"verdict": "atRisk",
"note": "Protected by a proof flavor documented to leak witness data."
},
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "Spend graph explorer built from Payy blocks (by L2BEAT)",
"url": "https://sekuba.github.io/payy-graph/"
},
{
"title": "UTXO circuit: spent and created commitments are public, no nullifier",
"url": "https://github.com/polybase/payy/blob/2f95947f12981a838f6f0c9dddace825bf835502/noir/utxo/src/main.nr#L9-L15"
},
{
"title": "Client proofs use the non-ZK Honk flavor",
"url": "https://github.com/polybase/payy/blob/2f95947f12981a838f6f0c9dddace825bf835502/pkg/barretenberg-rs/src/binding.rs#L109-L118"
},
{
"title": "Honk docs: the base flavor leaks witness information",
"url": "https://github.com/AztecProtocol/aztec-packages/blob/58bf73a289f7da78c8920c9c73604a8e5d105025/barretenberg/cpp/src/barretenberg/ultra_honk/README.md#zero-knowledge"
}
],
"id": "publicObserver",
"value": "Link exposed",
"alsoExposed": []
},
"chainAnalyst": {
"sentiment": "bad",
"exposureShort": "Along a path without splits or merges, the deposit and withdrawal amounts fix every amount in between.",
"exposureContinued": "Each wallet has one fixed deposit address, so all its deposits link to each other and to whoever funded them.",
"interior": {
"sender": {
"verdict": "atRisk",
"note": "Nodes are labelled by their terminal deposit and withdrawal addresses."
},
"recipient": "atRisk",
"amount": {
"verdict": "atRisk",
"note": "Inferable along a linear path from a deposit to a withdrawal."
},
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "Public block API",
"url": "https://validators.mainnet.payy.network/v0/blocks"
},
{
"title": "One deposit address stored per wallet",
"url": "https://github.com/polybase/payy/blob/2f95947f12981a838f6f0c9dddace825bf835502/pkg/database/src/schema.rs#L464-L481"
},
{
"title": "Deposit relayed from the deposit address with a signed USDC authorization",
"url": "https://github.com/polybase/payy/blob/2f95947f12981a838f6f0c9dddace825bf835502/pkg/guild-interface/src/mint.rs#L56-L90"
},
{
"title": "Wallet FAQ: the deposit address forwards to the bridge",
"url": "https://docs.payy.network/payy-wallet/payy-wallet-faq"
}
],
"id": "chainAnalyst",
"value": "Link exposed",
"alsoExposed": [
{
"field": "sender",
"exposure": "atRisk"
},
{
"field": "recipient",
"exposure": "atRisk"
}
]
},
"networkObserver": {
"sentiment": "bad",
"exposureShort": "The Payy app is closed source and no open client works on mainnet, so what it sends to third parties is up to Payy and can change at any time.",
"exposureContinued": "The payment-link website loads a third-party analytics script that records the page URL, which holds the link's redeem secret.",
"interior": {
"sender": "unverifiable",
"recipient": "unverifiable",
"amount": {
"verdict": "atRisk",
"note": "A link opened in a browser hands its redeem secret to the analytics provider."
},
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "The repository publishes only type bindings of the app",
"url": "https://github.com/polybase/payy/blob/2f95947f12981a838f6f0c9dddace825bf835502/app/packages/payy/src"
},
{
"title": "The open TypeScript client knows only dev and testnet",
"url": "https://github.com/polybase/payy/blob/2f95947f12981a838f6f0c9dddace825bf835502/app/packages/payy-client/src/network.ts#L6-L17"
},
{
"title": "Analytics with default settings on the link website",
"url": "https://github.com/polybase/payy/blob/2f95947f12981a838f6f0c9dddace825bf835502/app/packages/link/src/config/posthog.ts#L10-L18"
},
{
"title": "Send links carry the secret in the URL fragment",
"url": "https://github.com/polybase/payy/blob/2f95947f12981a838f6f0c9dddace825bf835502/pkg/parse-link/src/lib.rs#L50-L56"
}
],
"id": "networkObserver",
"value": "Link exposed",
"alsoExposed": [
{
"field": "sender",
"exposure": "unverifiable"
},
{
"field": "recipient",
"exposure": "unverifiable"
}
]
},
"privilegedInsider": {
"sentiment": "bad",
"exposureShort": "One company runs the only validator and prover, the node, the note registry, the deposit relayer and the KYC checks.",
"exposureContinued": "Its backend ties each session to a wallet address and keeps, per wallet, the deposit address, KYC record, country, IP country and the commitment and owner of every note the app reports. For payment links and fiat ramps it holds the notes' private keys and can read and spend them. Its registry sees which wallet delivers a note to which recipient key, and in which block.",
"interior": {
"sender": "exposed",
"recipient": "exposed",
"amount": {
"verdict": "atRisk",
"note": "The backend holds the keys of link and ramp notes."
},
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"contract": "RollupV1",
"title": "setRoot, provers, validators, burn substitutors"
},
{
"title": "Session bound to a wallet address by signature",
"url": "https://github.com/polybase/payy/blob/2f95947f12981a838f6f0c9dddace825bf835502/pkg/guild-interface/src/auth.rs#L1-L16"
},
{
"title": "Link and ramp notes are created with their private key on the backend",
"url": "https://github.com/polybase/payy/blob/2f95947f12981a838f6f0c9dddace825bf835502/pkg/guild-interface/src/notes/create.rs#L36-L45"
},
{
"title": "Wallet table: deposit address, KYC, country, IP country",
"url": "https://github.com/polybase/payy/blob/2f95947f12981a838f6f0c9dddace825bf835502/pkg/database/src/schema.rs#L464-L481"
}
],
"id": "privilegedInsider",
"value": "Link exposed",
"alsoExposed": [
{
"field": "sender",
"exposure": "exposed"
},
{
"field": "recipient",
"exposure": "exposed"
}
]
},
"futureAdversary": {
"sentiment": "bad",
"exposureShort": "The per-transaction proofs are public and not zero-knowledge, and the commitments inside them rest on elliptic curves.",
"exposureContinued": "Registry ciphertexts use elliptic-curve key exchange. If the operator retains them, whoever breaks elliptic-curve cryptography opens every note delivered through it.",
"exposureContinued": "How much more whoever breaks elliptic-curve cryptography extracts from those proofs is not established.",
"interior": {
"sender": {
"verdict": "atRisk",
"note": "Only if Payy retains the registry, whose ciphertexts are not on Ethereum."
},
"sender": "atRisk",
"recipient": "atRisk",
"amount": {
"verdict": "atRisk",
"note": "Public proofs are not zero-knowledge, and retained registry ciphertexts open."
},
"amount": "atRisk",
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "Registry encryption (X25519-XSalsa20-Poly1305)",
"url": "https://github.com/polybase/payy/blob/2f95947f12981a838f6f0c9dddace825bf835502/pkg/encrypt/src/asymmetric.rs#L80-L81"
},
{
"title": "Client proofs use the non-ZK Honk flavor",
"url": "https://github.com/polybase/payy/blob/2f95947f12981a838f6f0c9dddace825bf835502/pkg/barretenberg-rs/src/binding.rs#L109-L118"
},
{
"title": "Honk docs: ZK flavors add masking the base flavor lacks",
"url": "https://github.com/AztecProtocol/aztec-packages/blob/58bf73a289f7da78c8920c9c73604a8e5d105025/barretenberg/cpp/src/barretenberg/ultra_honk/README.md#zero-knowledge"
},
{
"contract": "HonkVerifier",
"title": "Onchain verifier (ZK flavor)"
}
],
"id": "futureAdversary",
"value": "Link exposed",
"alsoExposed": [
{
"field": "sender",
"exposure": "atRisk"
},
{
"field": "recipient",
"exposure": "atRisk"
}
]
}
}
},
"attributes": [
{
"id": "zk",
"label": "ZK",
"description": "Uses zero-knowledge proofs to prove private actions without revealing private data."
},
{
"id": "transfers",
"label": "Transfers",
"description": "Private transfers within the shielded pool."
},
{
"id": "anyAmount",
"label": "Any amount",
"description": "Deposits and withdrawals can have any size."
}
],
"category": {
"id": "shieldedLedger",
"label": "Shielded ledger",
"description": "A pool with transfers or DeFi inside. Hides who pays whom and which deposit became which withdrawal."
},
"detailedDescription": "Payy is a mobile app for USDC payments. The user deposits USDC, sends it to other users or as a payment link, and withdraws it to Ethereum or tops up the Payy card. Note amounts and owners stay hidden. Which notes fund which, and every deposit and withdrawal with its address and amount, are public.\n\nUsers trust Payy, which runs the only validator, prover and node, delivers notes between users and holds the keys of link and ramp notes. The 2/4 multisig can upgrade the RollupV1 contract and overwrite its state root without delay. Leaving needs Payy: withdrawals settle only in its proven state updates, and transaction data lives only on its servers.\n\n### Architecture\n\nEach balance is a set of notes. A note holds an amount of USDC and an owner key, and only its commitment enters the state tree. A transaction spends up to two notes, creates up to two and names the commitments it spends, since the circuits use no nullifiers. Payy's node serves every block with its proofs. Ethereum receives only state roots, deposits and withdrawals.\n\n### Flow\n\n1. **Deposit.** The app gives each wallet one fixed deposit address. You send USDC there, and Payy's relayer moves it into the RollupV1 contract with your signed authorization. Deposit address and amount are public.\n2. **Send.** Your phone proves the transfer and submits it to Payy's node. The note reaches the recipient through Payy's registry, encrypted to the recipient's key, or as a payment link whose URL holds the note's secret.\n3. **Withdraw.** You burn notes to an Ethereum address, which the next state update pays out. A whitelisted account may pay at once and get refunded at settlement. Recipient and amount are public. Card top-ups are withdrawals to the card issuer's contract.\n\n### Keys\n\nThe app is closed source, so how it creates and backs up keys is unverified. Payy's backend keeps wallet backups, and its diagnostics reports have a required field for the recovery phrase.\n\n### App\n\nThe ratings assume the Payy mobile app, which is closed source and talks only to Payy's servers. The [repository](https://github.com/polybase/payy) publishes the contracts, circuits, node and backend interfaces. Its open TypeScript client knows only Payy's testnet.\n\n### Compliance\n\nKYC is required for the Payy card and fiat ramps, not for transfers. Payy's backend can block a wallet or an IP address from its services, and its validator can refuse any transaction. The protocol has no view key.\n\n### Fees\n\nThe RollupV1 contract charges no fee. Payy pays the gas of deposits and settlement.",
"exitWindow": {
"value": "None",
"sentiment": "bad",
"orderHint": 0,
"description": "The PayyMultisig can instantly upgrade the RollupV1 contract, replace ZK verifiers and directly overwrite the state root, so users have no time to exit before a malicious change takes effect.",
"walkawayTest": {
"passed": false,
"reason": "Withdrawals must be included in a proven state update by the permissioned Payy operators. There is no mechanism for users to exit on Ethereum if the operators halt."
}
},
"reproducibility": {
"value": "Partially reproducible",
"sentiment": "warning",
"description": "The Payy app is closed source. The contracts, circuits and node are published without a license and can be built locally. Transaction data is not posted anywhere public, so the state cannot be rebuilt independently."
},
"riskSummary": "## Funds can be stolen if\n1. the verifier or the circuits accept an invalid withdrawal.\n2. the PayyMultisig upgrades the RollupV1 contract or overwrites the state root, which takes effect without delay.\n
\n## Funds can be lost if\n1. a user loses the note data or the keys required to spend their notes.\n2. the offchain transaction data becomes unavailable, as data availability is not verified on Ethereum.\n3. the operators stop including withdrawals in proven state updates, as there is no forced exit mechanism.\n
\n## Privacy can be lost if\n1. anyone with Payy's block data follows which notes fund which, from a deposit address to a withdrawal address (see public observer).\n2. a path without splits or merges reveals every amount between a deposit and a withdrawal (see chain analyst).\n3. the closed-source Payy app sends user data to third parties, which Payy can change at any time (see network observer).\n4. Payy's backend, which ties each wallet to its KYC record, deposit address and notes, leaks or uses this data (see privileged insider).\n5. the public per-transaction proofs, which are not zero-knowledge, or retained registry ciphertexts are opened in the future (see future adversary).",
"riskSummary": "## Funds can be stolen if\n1. the verifier or the circuits accept an invalid withdrawal.\n2. the PayyMultisig upgrades the RollupV1 contract or overwrites the state root, which takes effect without delay.\n
\n## Funds can be lost if\n1. a user loses the note data or the keys required to spend their notes.\n2. the offchain transaction data becomes unavailable, as data availability is not verified on Ethereum.\n3. the operators stop including withdrawals in proven state updates, as there is no forced exit mechanism.\n
\n## Privacy can be lost if\n1. anyone with Payy's block data follows which notes fund which, from a deposit address to a withdrawal address (see public observer).\n2. a path without splits or merges reveals every amount between a deposit and a withdrawal (see chain analyst).\n3. the closed-source Payy app sends user data to third parties, which Payy can change at any time (see network observer).\n4. Payy's backend, which ties each wallet to its KYC record, deposit address and notes, leaks or uses this data (see privileged insider).\n5. the public per-transaction proofs, which are not zero-knowledge, are opened in the future (see future adversary).",
"tokens": [],
"trackedOn": [
"ethereum"
],
"upgradesAndGovernance": {
"content": "All privileged functions are ultimately controlled by the PayyMultisig (2/4). It owns the ProxyAdmin, which can instantly upgrade the RollupV1 proxy, and it is the owner of the RollupV1 contract, allowing it to manage provers, validators, ZK verifiers, supported tokens and burn substitutors, and to directly overwrite the state root via setRoot(). There is no timelock or exit window on any of these actions."
},
"zkCatalogId": "barretenberg"
}
+2 -2
+2 -2
{
"adversaries": {
"promise": {
"protects": "linkage",
"text": "Hides everything inside the ledger, including which deposits fund a withdrawal. Deposits and withdrawals are public."
},
"adversaries": [
{
"id": "publicObserver",
"label": "Public observer",
"description": "Everyone with a block explorer and some basic tools. Sees every public onchain event, but does no correlation beyond following links.",
"examples": "A curious counterparty, an employer, a journalist."
},
{
"id": "chainAnalyst",
"label": "Chain analyst",
"description": "Scrapes all public data and correlates it: timing, amounts, gas and wallet fingerprints, address clusters.",
"examples": "Chain analytics firms, ZachXBT, data brokers."
},
{
"id": "networkObserver",
"label": "Network observer",
"description": "Sits between the user and the services and sees traffic only: ISPs, VPNs, Tor exits, public RPCs and relayers. Learns IP addresses, timing, fingerprints and ciphertext. Services the operator runs count as the insider.",
"examples": "Infura or Alchemy, a Tornado relayer, a wallet vendor selling telemetry, Google captcha or analytics in the dapp frontend."
},
{
"id": "privilegedInsider",
"label": "Privileged insider",
"description": "Holds an operator role, custodies funds, receives keys or plaintext by design, or delivers the client: upgrade admin, custodian, view key holder, enclave operator, association set provider, hosted prover, registry, frontend host.",
"examples": "A compliance backdoor key, a DAO with an upgrade key, a KMS committee, an ASP operator, a custodial bridge."
},
{
"id": "futureAdversary",
"label": "Future adversary",
"description": "Harvest now, decrypt later. Holds every byte ever written onchain plus any retained logs, and breaks all public-key cryptography, by quantum computer or new mathematics: elliptic curves, pairings, RSA, lattices and isogenies. Hashes, Poseidon included, and symmetric ciphers survive.",
"description": "Harvest now, decrypt later. Holds every byte ever published and runs the known quantum attacks: elliptic curves, pairings and RSA fall. Hashes, symmetric ciphers and post-quantum schemes stand until an attack on them is known.",
"examples": "An intelligence agency archiving chain data today, then anyone once a break is public."
}
],
"fields": [
{
"id": "sender",
"label": "Sender",
"subject": "Sender",
"promiseLabel": "Sender privacy",
"description": "The Ethereum address that funds entered from, or that initiated a transfer."
},
{
"id": "recipient",
"label": "Recipient",
"subject": "Recipient",
"promiseLabel": "Recipient privacy",
"description": "Who receives the funds: the address they exit to, the receiver of a transfer, or whoever controls a one-time receiving address."
},
{
"id": "amount",
"label": "Amount",
"subject": "Amounts",
"promiseLabel": "Amount privacy",
"description": "The value moved."
},
{
"id": "asset",
"label": "Asset",
"subject": "Asset",
"promiseLabel": "Asset privacy",
"description": "Which token is moved."
},
{
"id": "linkage",
"label": "Link",
"subject": "Link",
"promiseLabel": "Link privacy",
"description": "Whether the entry and exit of the same funds, or sender and recipient of the same transfer, can be tied together."
}
],
"cells": {
"publicObserver": {
"sentiment": "good",
"exposureShort": "Transfers inside publish only encrypted notes.",
"exposureContinued": "Deposits and withdrawals show address, token and amount. Each epoch pairs every exit with the nullifiers and note shape of the transfer that funded it. Forced withdrawals publish the spent notes and the account, public gift exits the destination.",
"advice": "Exit through the operator's relay.",
"interior": {
"sender": "private",
"recipient": "private",
"amount": {
"verdict": "atRisk",
"note": "Public in gateway DeFi legs."
},
"asset": {
"verdict": "atRisk",
"note": "Public in gateway DeFi legs."
},
"linkage": "private"
},
"sources": [
{
"contract": "PrivacyBoost"
},
{
"title": "Epoch calldata: withdrawals, nullifiers and transfer shapes",
"url": "https://github.com/sunnyside-io/privacy-boost-protocol/blob/5792c139b9529ed80643262d75b5489055be11b0/contracts/src/interfaces/IPrivacyBoost.sol#L828-L852"
},
{
"title": "Forced withdrawal publishes account and notes",
"url": "https://github.com/sunnyside-io/privacy-boost-protocol/blob/5792c139b9529ed80643262d75b5489055be11b0/contracts/src/interfaces/IPrivacyBoost.sol#L582-L591"
},
{
"title": "Public gift exit names the destination",
"url": "https://github.com/sunnyside-io/privacy-boost-protocol/blob/5792c139b9529ed80643262d75b5489055be11b0/contracts/src/interfaces/IPrivacyBoost.sol#L707"
}
],
"id": "publicObserver",
"value": "Link private",
"alsoExposed": []
},
"chainAnalyst": {
"sentiment": "bad",
"exposureShort": "The anonymity set is very small.",
"exposureContinued": "Most pool activity is one address that keeps depositing and withdrawing 0.001 WETH, which an analyst can filter out.",
"interior": {
"sender": "atRisk",
"recipient": "atRisk",
"amount": {
"verdict": "atRisk",
"note": "Bounded by the public deposit and exit amounts."
},
"asset": "atRisk",
"linkage": {
"verdict": "exposed",
"note": "The set is too small to hide in."
}
},
"sources": [
{
"title": "Address with 0.001 WETH round trips",
"url": "https://basescan.org/address/0xf977237b7d978dde922ee4909619740c73d8a49b"
}
],
"id": "chainAnalyst",
"value": "Link exposed",
"alsoExposed": [
{
"field": "sender",
"exposure": "atRisk"
},
{
"field": "recipient",
"exposure": "atRisk"
}
]
},
"networkObserver": {
"sentiment": "bad",
"exposureShort": "The SDK's core is closed source with no open alternative, so what it sends, and where, is up to the operator and can change with any release.",
"exposureContinued": "Today, anyone on the user's network path sees their wallet deposits and app contacts with the operator, and can match both to the chain. The SDK has no Tor or proxy setting, and the operator's server tells it which endpoints to use.",
"interior": {
"sender": "private",
"recipient": "private",
"amount": {
"verdict": "atRisk",
"note": "Public in gateway DeFi legs."
},
"asset": {
"verdict": "atRisk",
"note": "Public in gateway DeFi legs."
},
"linkage": {
"verdict": "atRisk",
"note": "Private only over Tor, which the SDK lacks."
}
},
"sources": [
{
"title": "Operator endpoint",
"url": "https://base.privacyboost.io/api/v1/info"
},
{
"title": "SDK 1.2.5, configured with one server URL",
"url": "https://www.npmjs.com/package/@sunnyside-io/privacy-boost/v/1.2.5"
},
{
"title": "The compiled core builds and sends every request, its Rust source is unpublished",
"url": "https://www.npmjs.com/package/@sunnyside-io/privacy-boost/v/1.2.5?activeTab=code"
}
],
"id": "networkObserver",
"value": "Link exposed",
"alsoExposed": []
},
"privilegedInsider": {
"sentiment": "bad",
"exposureShort": "The operator's enclave holds every transfer in plaintext and a key to every note.",
"exposureContinued": "The SDK trusts the enclave key it fetches from the operator's endpoint. Auditors appointed by the admin can pull any account's history without consent.",
"interior": {
"sender": "exposed",
"recipient": "exposed",
"amount": "exposed",
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"contract": "AuditGateway"
},
{
"section": "permissions",
"title": "Admin and operator multisigs"
},
{
"title": "SDK fetches the enclave key from the endpoint",
"url": "https://www.npmjs.com/package/@sunnyside-io/privacy-boost/v/1.2.5"
},
{
"title": "Notes wrap a key for the enclave beside the receiver",
"url": "https://github.com/sunnyside-io/privacy-boost-protocol/blob/5792c139b9529ed80643262d75b5489055be11b0/contracts/src/interfaces/IStructs.sol#L36-L56"
}
],
"id": "privilegedInsider",
"value": "Link exposed",
"alsoExposed": [
{
"field": "sender",
"exposure": "exposed"
},
{
"field": "recipient",
"exposure": "exposed"
},
{
"field": "amount",
"exposure": "exposed"
},
{
"field": "asset",
"exposure": "exposed"
}
]
},
"futureAdversary": {
"sentiment": "bad",
"exposureShort": "Every note wraps its key to the enclave's long-lived elliptic-curve public key as well as the receiver's.",
"exposureContinued": "Whoever breaks elliptic-curve cryptography or obtains that one key decrypts the entire history.",
"exposureContinued": "Whoever breaks elliptic-curve cryptography decrypts the entire history.",
"interior": {
"sender": "exposed",
"recipient": "exposed",
"amount": "exposed",
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "Every output and deposit ciphertext carries an enclave key",
"url": "https://github.com/sunnyside-io/privacy-boost-protocol/blob/5792c139b9529ed80643262d75b5489055be11b0/contracts/src/interfaces/IStructs.sol#L36-L125"
}
],
"id": "futureAdversary",
"value": "Link exposed",
"alsoExposed": [
{
"field": "sender",
"exposure": "exposed"
},
{
"field": "recipient",
"exposure": "exposed"
},
{
"field": "amount",
"exposure": "exposed"
},
{
"field": "asset",
"exposure": "exposed"
}
]
}
}
},
"anonymitySet": {
"type": "too-small"
},
"attributes": [
{
"id": "zk",
"label": "ZK",
"description": "Uses zero-knowledge proofs to prove private actions without revealing private data."
},
{
"id": "tee",
"label": "TEE",
"description": "Privacy assumptions of this project are secured by trusted hardware."
},
{
"id": "transfers",
"label": "Transfers",
"description": "Private transfers within the shielded pool."
},
{
"id": "defi",
"label": "DeFi",
"description": "Interop with DeFi (swaps, vaults) from within the shielded pool."
},
{
"id": "anyAmount",
"label": "Any amount",
"description": "Deposits and withdrawals can have any size."
}
],
"category": {
"id": "shieldedLedger",
"label": "Shielded ledger",
"description": "A pool with transfers or DeFi inside. Hides who pays whom and which deposit became which withdrawal."
},
"exitWindow": {
"value": "None",
"sentiment": "bad",
"orderHint": 0,
"description": "The admin multisig upgrades the pool and both registries instantly through their ProxyAdmins.",
"walkawayTest": {
"passed": false,
"reason": "Without the TEE operator, deposits and private transfers stop and only forced withdrawals remain."
}
},
"reproducibility": {
"value": "Partially reproducible",
"sentiment": "warning",
"description": "The circuits are published. The epoch, forced withdrawal and gift claim verification keys deployed in September 2026 remain unreproduced, and the source code of the TEE and of the SDK's compiled core is unpublished."
},
"riskSummary": "## Funds can be stolen if\n1. the zk proof system is broken, allowing invalid spends or withdrawals.\n2. all [trusted setup](#trusted-setups) participants collude or leak their secrets, allowing forged proofs.\n3. the admin multisig deploys a malicious [upgrade](#upgrades-and-governance) or registers a malicious verifying key.\n
\n## Funds can be lost if\n1. a user loses their note secrets, or both the account-owner wallet and every usable authorization key.\n
\n## Privacy can be lost if\n1. the TEE or its hardware vendor is compromised (see privileged insider).\n2. an auditor appointed by the admin multisig fetches the user's history through the Audit API (see privileged insider).\n3. a user exits through a forced withdrawal (see public observer).\n4. a user relies on today's anonymity set, which is too small to hide in (see chain analyst).\n5. the operator changes the SDK's closed-source core to send user data elsewhere, which users cannot check (see network observer).",
"tokens": [
{
"token": {
"address": "0x4200000000000000000000000000000000000006",
"iconUrl": "https://coin-images.coingecko.com/coins/images/2518/large/weth.png?1696503332",
"symbol": "WETH",
"decimals": 18,
"priceId": "weth",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-WETH",
"type": "pool",
"label": "WETH",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"iconUrl": "https://assets.coingecko.com/coins/images/6319/large/usdc.png?1696506694",
"symbol": "USDC",
"decimals": 6,
"priceId": "usd-coin",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-USDC",
"type": "pool",
"label": "USDC",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
"iconUrl": "https://coin-images.coingecko.com/coins/images/40143/large/cbbtc.webp?1726136727",
"symbol": "cbBTC",
"decimals": 8,
"priceId": "coinbase-wrapped-btc",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-cbBTC",
"type": "pool",
"label": "cbBTC",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42",
"iconUrl": "https://coin-images.coingecko.com/coins/images/26045/large/euro.png?1696525125",
"symbol": "EURC",
"decimals": 6,
"priceId": "euro-coin",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-EURC",
"type": "pool",
"label": "EURC",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0x311935Cd80B76769bF2ecC9D8Ab7635b2139cf82",
"iconUrl": "https://coin-images.coingecko.com/coins/images/4128/large/solana.png?1718769756",
"symbol": "SOL",
"decimals": 9,
"priceId": "solana",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-SOL",
"type": "pool",
"label": "SOL",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2",
"iconUrl": "https://coin-images.coingecko.com/coins/images/39963/large/usdt.png?1724952731",
"symbol": "USDT",
"decimals": 6,
"priceId": "l2-standard-bridged-usdt-base",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-USDT",
"type": "pool",
"label": "USDT",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0x940181a94A35A4569E4529A3CDfB74e38FD98631",
"iconUrl": "https://assets.coingecko.com/coins/images/31745/large/token.png?1696530564",
"symbol": "AERO",
"decimals": 18,
"priceId": "aerodrome-finance",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-AERO",
"type": "pool",
"label": "AERO",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0xB2000000000000000000004c27f6523082f41D01",
"iconUrl": "https://coin-images.coingecko.com/coins/images/102175780/large/zi54rndmdx59nblfgry3d1pyckch.?1787558766",
"symbol": "Basecat",
"decimals": 18,
"priceId": "basecat",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-Basecat",
"type": "pool",
"label": "Basecat",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
"iconUrl": "https://coin-images.coingecko.com/coins/images/18834/large/wstETH.png?1696518295",
"symbol": "wstETH",
"decimals": 18,
"priceId": "wrapped-steth",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-wstETH",
"type": "pool",
"label": "wstETH",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0xb200000000000000000000C2e324d24d7eEcd1fb",
"iconUrl": "https://coin-images.coingecko.com/coins/images/102175597/large/aapl_200x200.png?1787068801",
"symbol": "AAPLc",
"decimals": 8,
"priceId": "apple-coinbase-tokenized-stock",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-AAPLc",
"type": "pool",
"label": "AAPLc",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0xcb585250f852C6c6bf90434AB21A00f02833a4af",
"iconUrl": "https://coin-images.coingecko.com/coins/images/66267/large/Coinbase_Wrapped_XPR_%28cbXRP%29.png?1749023398",
"symbol": "cbXRP",
"decimals": 6,
"priceId": "coinbase-wrapped-xrp",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-cbXRP",
"type": "pool",
"label": "cbXRP",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0xAC1Bd2486aAf3B5C0fc3Fd868558b082a531B2B4",
"iconUrl": "https://assets.coingecko.com/coins/images/31126/large/2023-08-11_13.21.24.png?1697025145",
"symbol": "TOSHI",
"decimals": 18,
"priceId": "toshi",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-TOSHI",
"type": "pool",
"label": "TOSHI",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0x532f27101965dd16442E59d40670FaF5eBB142E4",
"iconUrl": "https://assets.coingecko.com/coins/images/35529/large/1000050750.png?1709031995",
"symbol": "BRETT",
"decimals": 18,
"priceId": "based-brett",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-BRETT",
"type": "pool",
"label": "BRETT",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0xbeeff7aE5E00Aae3Db302e4B0d8C883810a58100",
"iconUrl": "https://coin-images.coingecko.com/coins/images/6319/large/USDC.png?1769615602",
"symbol": "bbqUSDC",
"decimals": 18,
"priceId": "usd-coin",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-bbqUSDC",
"type": "pool",
"label": "bbqUSDC",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0x1deEfABEe758AAbdC29a542B24ca3b75aFD56765",
"iconUrl": "https://coin-images.coingecko.com/coins/images/6319/large/USDC.png?1769615602",
"symbol": "gtusdcf",
"decimals": 18,
"priceId": "usd-coin",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-gtusdcf",
"type": "pool",
"label": "gtusdcf",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0xFeFeC33668E22677c4762d0853d56245a800ff08",
"iconUrl": "https://coin-images.coingecko.com/coins/images/2518/large/weth.png?1696503332",
"symbol": "gtwethb",
"decimals": 18,
"priceId": "weth",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-gtwethb",
"type": "pool",
"label": "gtwethb",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0x1D3b1Cd0a0f242d598834b3F2d126dC6bd774657",
"iconUrl": "https://coin-images.coingecko.com/coins/images/6319/large/USDC.png?1769615602",
"symbol": "CSUSDC",
"decimals": 18,
"priceId": "usd-coin",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-CSUSDC",
"type": "pool",
"label": "CSUSDC",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
},
{
"token": {
"address": "0x5435BC53f2C61298167cdB11Cdf0Db2BFa259ca0",
"iconUrl": "https://coin-images.coingecko.com/coins/images/6319/large/USDC.png?1769615602",
"symbol": "edgeUSDC",
"decimals": 18,
"priceId": "usd-coin",
"sinceTimestamp": 1788377831
},
"buckets": [
{
"id": "privacy-boost-edgeUSDC",
"type": "pool",
"label": "edgeUSDC",
"address": "base:0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40",
"sinceTimestamp": 1788377831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x71A0fD3C76E3E937d8275A3cb6a467b70123bD40"
}
}
}
]
}
],
"trackedOn": [
"base"
],
"upgradesAndGovernance": {
"content": "The 3/4 admin multisig upgrades the pool, registries and AuditGateway instantly. It can replace all five verifiers and their keys, set withdrawal and portal fees up to 10% each, configure portal minimum sweeps, appoint auditors, and change the treasury, operator and gateway route manager.\n\nThe gateway owner manages target and selector policies, picks the guardian and can pause execution. The guardian can pause and remove policies. Stranded gateway tokens return to the pool only while paused."
}
}
+2 -2
+2 -2
{
"adversaries": {
"promise": {
"protects": "linkage",
"text": "Hides which deposit funds which withdrawal, for deposits the ASP approves. Everything else is public."
},
"adversaries": [
{
"id": "publicObserver",
"label": "Public observer",
"description": "Everyone with a block explorer and some basic tools. Sees every public onchain event, but does no correlation beyond following links.",
"examples": "A curious counterparty, an employer, a journalist."
},
{
"id": "chainAnalyst",
"label": "Chain analyst",
"description": "Scrapes all public data and correlates it: timing, amounts, gas and wallet fingerprints, address clusters.",
"examples": "Chain analytics firms, ZachXBT, data brokers."
},
{
"id": "networkObserver",
"label": "Network observer",
"description": "Sits between the user and the services and sees traffic only: ISPs, VPNs, Tor exits, public RPCs and relayers. Learns IP addresses, timing, fingerprints and ciphertext. Services the operator runs count as the insider.",
"examples": "Infura or Alchemy, a Tornado relayer, a wallet vendor selling telemetry, Google captcha or analytics in the dapp frontend."
},
{
"id": "privilegedInsider",
"label": "Privileged insider",
"description": "Holds an operator role, custodies funds, receives keys or plaintext by design, or delivers the client: upgrade admin, custodian, view key holder, enclave operator, association set provider, hosted prover, registry, frontend host.",
"examples": "A compliance backdoor key, a DAO with an upgrade key, a KMS committee, an ASP operator, a custodial bridge."
},
{
"id": "futureAdversary",
"label": "Future adversary",
"description": "Harvest now, decrypt later. Holds every byte ever written onchain plus any retained logs, and breaks all public-key cryptography, by quantum computer or new mathematics: elliptic curves, pairings, RSA, lattices and isogenies. Hashes, Poseidon included, and symmetric ciphers survive.",
"description": "Harvest now, decrypt later. Holds every byte ever published and runs the known quantum attacks: elliptic curves, pairings and RSA fall. Hashes, symmetric ciphers and post-quantum schemes stand until an attack on them is known.",
"examples": "An intelligence agency archiving chain data today, then anyone once a break is public."
}
],
"fields": [
{
"id": "sender",
"label": "Sender",
"subject": "Sender",
"promiseLabel": "Sender privacy",
"description": "The Ethereum address that funds entered from, or that initiated a transfer."
},
{
"id": "recipient",
"label": "Recipient",
"subject": "Recipient",
"promiseLabel": "Recipient privacy",
"description": "Who receives the funds: the address they exit to, the receiver of a transfer, or whoever controls a one-time receiving address."
},
{
"id": "amount",
"label": "Amount",
"subject": "Amounts",
"promiseLabel": "Amount privacy",
"description": "The value moved."
},
{
"id": "asset",
"label": "Asset",
"subject": "Asset",
"promiseLabel": "Asset privacy",
"description": "Which token is moved."
},
{
"id": "linkage",
"label": "Link",
"subject": "Link",
"promiseLabel": "Link privacy",
"description": "Whether the entry and exit of the same funds, or sender and recipient of the same transfer, can be tied together."
}
],
"cells": {
"publicObserver": {
"sentiment": "good",
"exposureShort": "A zero-knowledge proof hides which approved deposit a withdrawal spends.",
"exposureContinued": "Partial withdrawals leave a change note and look like full ones.",
"advice": "Exit through a relayer, so none of the user's wallets pay gas for the receiving address. Ragequit only deposits the user never withdrew from, since ragequitting a change note reveals the withdrawal that left it.",
"sources": [
{
"contract": "PrivacyPoolsEntrypoint"
},
{
"title": "Withdrawal circuit",
"url": "https://github.com/0xbow-io/privacy-pools-core/blob/a80836a47451e662f127af17e11430ffa976c234/packages/circuits/circuits/withdraw.circom"
},
{
"contract": "PrivacyPoolETH",
"title": "ragequit: only the depositing address, in public"
}
],
"id": "publicObserver",
"value": "Link private",
"alsoExposed": []
},
"chainAnalyst": {
"sentiment": "good",
"exposureShort": "A relayed withdrawal of a common amount hides among all approved deposits of its pool.",
"exposureContinued": "The approved list at any block is public. Any amount is allowed, so an unusual one pairs a deposit with its withdrawal. Paying gas from the user's wallet instead of a relayer exposes its fingerprint, account implementation and fee habits, even from a fresh address.",
"advice": "Use a pool with a large anonymity set. Withdraw common amounts rather than everything at once. Wait before exiting and pick a different time of day than the deposit. Exit to a fresh address every time and spend from it with a different wallet than the one that deposited.",
"sources": [
{
"contract": "PrivacyPoolsEntrypoint",
"title": "relay: anyone can relay, the fee comes from the withdrawal"
},
{
"title": "Blockchain Privacy and Regulatory Compliance (design paper)",
"url": "https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4563364"
},
{
"title": "Tutela (arXiv:2201.06811)",
"url": "https://arxiv.org/abs/2201.06811"
}
],
"id": "chainAnalyst",
"value": "Link private",
"alsoExposed": []
},
"networkObserver": {
"sentiment": "good",
"exposureShort": "The website works in Tor Browser and scans every pool whole, matching notes locally without revealing the user's deposits to third parties.",
"exposureContinued": "The relayer receives amount and asset for a quote and the recipient once the user confirms. With a wallet sign-in on the default RPC, Alchemy sees the wallet and then the polling for the user's withdrawal, tying the two by timing.",
"advice": "Withdraw in a new Tor Browser session, signed in with the user's recovery phrase so no wallet address is queried. Before signing in, set the user's own node as the Ethereum endpoint.",
"sources": [
{
"title": "Sign-in with a recovery phrase needs no wallet",
"url": "https://github.com/0xbow-io/privacy-pools-website/blob/7df411128f7a18a61a77f7a0371bf0b857969e2a/src/providers/AuthProvider.tsx#L39-L47"
},
{
"title": "Pools scanned whole from deployment",
"url": "https://github.com/0xbow-io/privacy-pools-website/blob/7df411128f7a18a61a77f7a0371bf0b857969e2a/src/utils/dataService.ts#L11-L34"
},
{
"title": "A custom endpoint takes over reads and scans",
"url": "https://github.com/0xbow-io/privacy-pools-website/blob/7df411128f7a18a61a77f7a0371bf0b857969e2a/src/config/chainData.ts#L660-L689"
},
{
"title": "Recipient sent to the relayer on confirm",
"url": "https://github.com/0xbow-io/privacy-pools-website/blob/7df411128f7a18a61a77f7a0371bf0b857969e2a/src/utils/quotePhases.ts#L4-L43"
}
],
"id": "networkObserver",
"value": "Link private",
"alsoExposed": []
},
"privilegedInsider": {
"sentiment": "warning",
"exposureShort": "The ASP postman can publish a new approved list at any time with no delay, and withdrawals must prove against the latest one.",
"exposureContinued": "It can deny the user a private exit or publish a list containing only their deposit, reducing their anonymity set to one. The website counts the anonymity set it shows from 0xbow's own feed, not from the list the user's withdrawal proves against. 0xbow can also change the hosted website at any time.",
"advice": "Before withdrawing, check the size of the approved list behind the latest root, which its RootUpdated event links on IPFS. Run an inspected local build of the client instead of the hosted frontend.",
"sources": [
{
"contract": "PrivacyPoolsEntrypoint",
"title": "updateRoot: the postman sets a new root with no delay"
},
{
"contract": "PrivacyPoolETH",
"title": "validWithdrawal: only the latest ASP root is accepted"
},
{
"title": "Displayed anonymity set counted from 0xbow's amount feed",
"url": "https://github.com/0xbow-io/privacy-pools-website/blob/7df411128f7a18a61a77f7a0371bf0b857969e2a/src/hooks/useASP.ts#L63-L75"
},
{
"section": "permissions",
"title": "Privacy Pools Multisig and ASP postman"
}
],
"id": "privilegedInsider",
"value": "Link at risk",
"alsoExposed": []
},
"futureAdversary": {
"sentiment": "good",
"exposureShort": "Nothing encrypted is written onchain and commitments are hashes, so whoever breaks public-key cryptography recovers nothing from the chain.",
"exposureShort": "Nothing encrypted is written onchain and commitments are Poseidon hashes, so whoever breaks elliptic-curve cryptography recovers nothing from the chain.",
"exposureContinued": "Accounts created from a wallet signature reduce to that wallet's key.",
"advice": "Create the user's account from a recovery phrase, not from a wallet signature.",
"sources": [
{
"title": "Commitment circuit (Poseidon)",
"url": "https://github.com/0xbow-io/privacy-pools-core/blob/a80836a47451e662f127af17e11430ffa976c234/packages/circuits/circuits/commitment.circom"
},
{
"title": "Wallet-signature seed derivation",
"url": "https://github.com/0xbow-io/privacy-pools-website/blob/7df411128f7a18a61a77f7a0371bf0b857969e2a/src/utils/walletSeed.ts#L40-L73"
},
{
"title": "Random recovery phrase option",
"url": "https://github.com/0xbow-io/privacy-pools-website/blob/7df411128f7a18a61a77f7a0371bf0b857969e2a/src/utils/seedPhrase.ts#L3-L7"
},
{
"section": "trusted-setups"
}
],
"id": "futureAdversary",
"value": "Link private",
"alsoExposed": []
}
}
},
"attributes": [
{
"id": "zk",
"label": "ZK",
"description": "Uses zero-knowledge proofs to prove private actions without revealing private data."
},
{
"id": "anyAmount",
"label": "Any amount",
"description": "Deposits and withdrawals can have any size."
}
],
"category": {
"id": "pool",
"label": "Pool",
"description": "Funds enter a shared pool and leave it later, with no actions inside. Hides which deposit became which withdrawal."
},
"exitWindow": {
"value": "Infinite",
"sentiment": "good",
"orderHint": 9007199254740991,
"description": "The depositing address can always ragequit its funds from the immutable pools, without the Entrypoint or the ASP. A ragequit is public.",
"walkawayTest": {
"passed": false,
"reason": "Private withdrawals need the ASP to approve each deposit and keep posting roots."
}
},
"relayerTracking": {
"type": "onchainEvents",
"sources": [
{
"address": "eth:0x6818809EefCe719E480a7526D76bD3e561526b46",
"sinceTimestamp": 1743265247,
"extractor": "privacyPoolsWithdrawalRelayed"
}
]
},
"reproducibility": {
"value": "Reproducible",
"sentiment": "good",
"description": "The contracts, circuits, SDK, relayer and website are open source and build locally. The ASP service is closed."
},
"riskSummary": "## Funds can be stolen if\n1. the zk proof system is broken, allowing invalid withdrawals.\n2. the [trusted setup](#trusted-setups) is compromised or all ceremony participants collude, allowing invalid withdrawals.\n3. the Entrypoint owner deploys a malicious [upgrade](#upgrades-and-governance) that steals new deposits or withdrawals relayed after it.\n
\n## Funds can be lost if\n1. a user loses the recovery phrase that their notes derive from.\n
\n## Privacy can be lost if\n1. the ASP leaves deposits out of its latest list, which blocks their private exit, up to halting all private withdrawals (see privileged insider).\n2. the ASP keeps only a few deposits in its latest list, so withdrawals proven against it point to one of them (see privileged insider).\n3. both relayers on the website refuse a withdrawal, so the user must self-relay or find a relayer elsewhere (see chain analyst).\n4. a user withdraws signed in with a wallet on the default RPC, so Alchemy ties the wallet to the withdrawal by timing (see network observer).",
"tokens": [
{
"token": {
"address": "0x6440f144b7e50D6a8439336510312d2F54beB01D",
"iconUrl": "https://coin-images.coingecko.com/coins/images/56069/large/BOLD_logo.png?1748265087",
"symbol": "BOLD",
"decimals": 18,
"priceId": "liquity-bold-2",
"sinceTimestamp": 1770806867
},
"buckets": [
{
"id": "privacy-pools-BOLD",
"type": "pool",
"label": "BOLD pool",
"address": "eth:0xb4b5Fd38Fd4788071d7287e3cB52948e0d10b23E",
"sinceTimestamp": 1770806867,
"deposit": {
"event": "0xe3b53cd1a44fbf11535e145d80b8ef1ed6d57a73bf5daa7e939b6b01657d6549",
"extractor": "privacyPoolsValue",
"params": {}
},
"withdrawal": {
"event": "0x75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21",
"extractor": "privacyPoolsValue",
"params": {}
}
}
]
},
{
"token": {
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"iconUrl": "https://assets.coingecko.com/coins/images/9956/large/Badge_Dai.png?1696509996",
"symbol": "DAI",
"decimals": 18,
"priceId": "dai",
"sinceTimestamp": 1752848471
},
"buckets": [
{
"id": "privacy-pools-DAI",
"type": "pool",
"label": "DAI pool",
"address": "eth:0x1c31C03B8CB2EE674D0F11De77135536db828257",
"sinceTimestamp": 1752848471,
"anonymitySet": {
"minimumAmounts": [
"200000000000000000000",
"20000000000000000000000"
]
},
"deposit": {
"event": "0xe3b53cd1a44fbf11535e145d80b8ef1ed6d57a73bf5daa7e939b6b01657d6549",
"extractor": "privacyPoolsValue",
"params": {}
},
"withdrawal": {
"event": "0x75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21",
"extractor": "privacyPoolsValue",
"params": {}
}
}
]
},
{
"token": {
"address": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
"iconUrl": "https://assets.coingecko.com/coins/images/279/large/ethereum.png?1595348880",
"symbol": "ETH",
"decimals": 18,
"priceId": "ethereum",
"sinceTimestamp": 1743265259
},
"buckets": [
{
"id": "privacy-pools-ETH",
"type": "pool",
"label": "ETH pool",
"address": "eth:0xF241d57C6DebAe225c0F2e6eA1529373C9A9C9fB",
"sinceTimestamp": 1743265259,
"anonymitySet": {
"minimumAmounts": [
"100000000000000000",
"10000000000000000000"
]
},
"deposit": {
"event": "0xe3b53cd1a44fbf11535e145d80b8ef1ed6d57a73bf5daa7e939b6b01657d6549",
"extractor": "privacyPoolsValue",
"params": {}
},
"withdrawal": {
"event": "0x75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21",
"extractor": "privacyPoolsValue",
"params": {}
}
}
]
},
{
"token": {
"address": "0xCAcd6fd266aF91b8AeD52aCCc382b4e165586E29",
"iconUrl": "https://coin-images.coingecko.com/coins/images/53963/large/frxUSD.png?1737792154",
"symbol": "frxUSD",
"decimals": 18,
"priceId": "frax-usd",
"sinceTimestamp": 1754583623
},
"buckets": [
{
"id": "privacy-pools-frxUSD",
"type": "pool",
"label": "frxUSD pool",
"address": "eth:0xC6C769fac7AABEadd31a03fAe5Ca0Ec5B4C50f84",
"sinceTimestamp": 1754583623,
"deposit": {
"event": "0xe3b53cd1a44fbf11535e145d80b8ef1ed6d57a73bf5daa7e939b6b01657d6549",
"extractor": "privacyPoolsValue",
"params": {}
},
"withdrawal": {
"event": "0x75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21",
"extractor": "privacyPoolsValue",
"params": {}
}
}
]
},
{
"token": {
"address": "0x085780639CC2cACd35E474e71f4d000e2405d8f6",
"iconUrl": "https://coin-images.coingecko.com/coins/images/36202/large/fxUSD.jpg?1710833113",
"symbol": "fxUSD",
"decimals": 18,
"priceId": "f-x-protocol-fxusd",
"sinceTimestamp": 1765446455
},
"buckets": [
{
"id": "privacy-pools-fxUSD",
"type": "pool",
"label": "fxUSD pool",
"address": "eth:0xD14F4B36E1D1D98c218db782c49149876042BC56",
"sinceTimestamp": 1765446455,
"deposit": {
"event": "0xe3b53cd1a44fbf11535e145d80b8ef1ed6d57a73bf5daa7e939b6b01657d6549",
"extractor": "privacyPoolsValue",
"params": {}
},
"withdrawal": {
"event": "0x75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21",
"extractor": "privacyPoolsValue",
"params": {}
}
}
]
},
{
"token": {
"address": "0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD",
"iconUrl": "https://coin-images.coingecko.com/coins/images/52721/large/sUSDS_Coin.png?1734086971",
"symbol": "sUSDS",
"decimals": 18,
"priceId": "susds",
"sinceTimestamp": 1752782999
},
"buckets": [
{
"id": "privacy-pools-sUSDS",
"type": "pool",
"label": "sUSDS pool",
"address": "eth:0xBBdA2173CDFEA1c3bD7F2908798F1265301d750c",
"sinceTimestamp": 1752782999,
"deposit": {
"event": "0xe3b53cd1a44fbf11535e145d80b8ef1ed6d57a73bf5daa7e939b6b01657d6549",
"extractor": "privacyPoolsValue",
"params": {}
},
"withdrawal": {
"event": "0x75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21",
"extractor": "privacyPoolsValue",
"params": {}
}
}
]
},
{
"token": {
"address": "0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d",
"iconUrl": "https://coin-images.coingecko.com/coins/images/54977/large/USD1_1000x1000_transparent.png?1749297002",
"symbol": "USD1",
"decimals": 18,
"priceId": "usd1-wlfi",
"sinceTimestamp": 1754583179
},
"buckets": [
{
"id": "privacy-pools-USD1",
"type": "pool",
"label": "USD1 pool",
"address": "eth:0xc0A8Bc0F4F982b4d4f1fFae8F4FCCb58c9B29c98",
"sinceTimestamp": 1754583179,
"deposit": {
"event": "0xe3b53cd1a44fbf11535e145d80b8ef1ed6d57a73bf5daa7e939b6b01657d6549",
"extractor": "privacyPoolsValue",
"params": {}
},
"withdrawal": {
"event": "0x75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21",
"extractor": "privacyPoolsValue",
"params": {}
}
}
]
},
{
"token": {
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"iconUrl": "https://assets.coingecko.com/coins/images/6319/large/usdc.png?1696506694",
"symbol": "USDC",
"decimals": 6,
"priceId": "usd-coin",
"sinceTimestamp": 1753353035
},
"buckets": [
{
"id": "privacy-pools-USDC",
"type": "pool",
"label": "USDC pool",
"address": "eth:0xb419c2867aB3CBc78921660cB95150d95A94ce86",
"sinceTimestamp": 1753353035,
"anonymitySet": {
"minimumAmounts": [
"200000000",
"20000000000"
]
},
"deposit": {
"event": "0xe3b53cd1a44fbf11535e145d80b8ef1ed6d57a73bf5daa7e939b6b01657d6549",
"extractor": "privacyPoolsValue",
"params": {}
},
"withdrawal": {
"event": "0x75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21",
"extractor": "privacyPoolsValue",
"params": {}
}
}
]
},
{
"token": {
"address": "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3",
"iconUrl": "https://assets.coingecko.com/coins/images/33613/large/3466ef_3c088c66c7d941e8856339d0bddf33cc_mv2.png?1702514458",
"symbol": "USDe",
"decimals": 18,
"priceId": "ethena-usde",
"sinceTimestamp": 1754583083
},
"buckets": [
{
"id": "privacy-pools-USDe",
"type": "pool",
"label": "USDe pool",
"address": "eth:0xe6D36B33b00A7C0cB0C2a8d39D07e7dB0c526Abc",
"sinceTimestamp": 1754583083,
"deposit": {
"event": "0xe3b53cd1a44fbf11535e145d80b8ef1ed6d57a73bf5daa7e939b6b01657d6549",
"extractor": "privacyPoolsValue",
"params": {}
},
"withdrawal": {
"event": "0x75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21",
"extractor": "privacyPoolsValue",
"params": {}
}
}
]
},
{
"token": {
"address": "0xdC035D45d973E3EC169d2276DDab16f1e407384F",
"iconUrl": "https://coin-images.coingecko.com/coins/images/39926/large/usds.webp?1726666683",
"symbol": "USDS",
"decimals": 18,
"priceId": "usds",
"sinceTimestamp": 1752503003
},
"buckets": [
{
"id": "privacy-pools-USDS",
"type": "pool",
"label": "USDS pool",
"address": "eth:0x05e4DBD71B56861eeD2Aaa12d00A797F04B5D3c0",
"sinceTimestamp": 1752503003,
"deposit": {
"event": "0xe3b53cd1a44fbf11535e145d80b8ef1ed6d57a73bf5daa7e939b6b01657d6549",
"extractor": "privacyPoolsValue",
"params": {}
},
"withdrawal": {
"event": "0x75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21",
"extractor": "privacyPoolsValue",
"params": {}
}
}
]
},
{
"token": {
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"iconUrl": "https://assets.coingecko.com/coins/images/325/large/Tether.png?1696501661",
"symbol": "USDT",
"decimals": 6,
"priceId": "tether",
"sinceTimestamp": 1753352915
},
"buckets": [
{
"id": "privacy-pools-USDT",
"type": "pool",
"label": "USDT pool",
"address": "eth:0xe859C0bD25f260BaEE534Fb52e307D3b64D24572",
"sinceTimestamp": 1753352915,
"anonymitySet": {
"minimumAmounts": [
"200000000",
"20000000000"
]
},
"deposit": {
"event": "0xe3b53cd1a44fbf11535e145d80b8ef1ed6d57a73bf5daa7e939b6b01657d6549",
"extractor": "privacyPoolsValue",
"params": {}
},
"withdrawal": {
"event": "0x75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21",
"extractor": "privacyPoolsValue",
"params": {}
}
}
]
},
{
"token": {
"address": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
"iconUrl": "https://assets.coingecko.com/coins/images/7598/large/wrapped_bitcoin_wbtc.png?1696507857",
"symbol": "WBTC",
"decimals": 8,
"priceId": "wrapped-bitcoin",
"sinceTimestamp": 1753975703
},
"buckets": [
{
"id": "privacy-pools-WBTC",
"type": "pool",
"label": "WBTC pool",
"address": "eth:0xF973f4B180A568157Cd7A0E6006449139E6Bfc32",
"sinceTimestamp": 1753975703,
"deposit": {
"event": "0xe3b53cd1a44fbf11535e145d80b8ef1ed6d57a73bf5daa7e939b6b01657d6549",
"extractor": "privacyPoolsValue",
"params": {}
},
"withdrawal": {
"event": "0x75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21",
"extractor": "privacyPoolsValue",
"params": {}
}
}
]
},
{
"token": {
"address": "0xDcEe70654261AF21C44c093C300eD3Bb97b78192",
"iconUrl": "https://coin-images.coingecko.com/coins/images/29734/large/woeth-200x200.png?1714796686",
"symbol": "wOETH",
"decimals": 18,
"priceId": "wrapped-oeth",
"sinceTimestamp": 1756377743
},
"buckets": [
{
"id": "privacy-pools-wOETH",
"type": "pool",
"label": "wOETH pool",
"address": "eth:0x7d2959bCFb936a84531518e8391DdBa844e03ebE",
"sinceTimestamp": 1756377743,
"deposit": {
"event": "0xe3b53cd1a44fbf11535e145d80b8ef1ed6d57a73bf5daa7e939b6b01657d6549",
"extractor": "privacyPoolsValue",
"params": {}
},
"withdrawal": {
"event": "0x75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21",
"extractor": "privacyPoolsValue",
"params": {}
}
}
]
},
{
"token": {
"address": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0",
"iconUrl": "https://assets.coingecko.com/coins/images/18834/large/wstETH.png?1696518295",
"symbol": "wstETH",
"decimals": 18,
"priceId": "wrapped-steth",
"sinceTimestamp": 1753975583
},
"buckets": [
{
"id": "privacy-pools-wstETH",
"type": "pool",
"label": "wstETH pool",
"address": "eth:0x1A604E9DFa0EFDC7FFda378AF16Cb81243b61633",
"sinceTimestamp": 1753975583,
"deposit": {
"event": "0xe3b53cd1a44fbf11535e145d80b8ef1ed6d57a73bf5daa7e939b6b01657d6549",
"extractor": "privacyPoolsValue",
"params": {}
},
"withdrawal": {
"event": "0x75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21",
"extractor": "privacyPoolsValue",
"params": {}
}
}
]
}
],
"trackedOn": [
"ethereum"
],
"upgradesAndGovernance": {
"content": "The 2/4 Privacy Pools Multisig holds the Entrypoint's owner role. It can upgrade the Entrypoint, register, configure and wind down pools, set fees and withdraw the vetting fees, all without delay. It also appoints the ASP postmen, who post the approved roots. The pools and verifiers are immutable. Relayed withdrawals and new deposits pass through the Entrypoint, so a malicious upgrade can steal them. Ragequit works without the Entrypoint, so funds already in the pools can always leave to their depositing addresses."
}
}
+1 -1
+1 -1
{
"adversaries": {
"promise": {
"protects": "linkage",
"text": "Hides everything inside the pool, including which shield funds which unshield. Shields and unshields are public."
},
"adversaries": [
{
"id": "publicObserver",
"label": "Public observer",
"description": "Everyone with a block explorer and some basic tools. Sees every public onchain event, but does no correlation beyond following links.",
"examples": "A curious counterparty, an employer, a journalist."
},
{
"id": "chainAnalyst",
"label": "Chain analyst",
"description": "Scrapes all public data and correlates it: timing, amounts, gas and wallet fingerprints, address clusters.",
"examples": "Chain analytics firms, ZachXBT, data brokers."
},
{
"id": "networkObserver",
"label": "Network observer",
"description": "Sits between the user and the services and sees traffic only: ISPs, VPNs, Tor exits, public RPCs and relayers. Learns IP addresses, timing, fingerprints and ciphertext. Services the operator runs count as the insider.",
"examples": "Infura or Alchemy, a Tornado relayer, a wallet vendor selling telemetry, Google captcha or analytics in the dapp frontend."
},
{
"id": "privilegedInsider",
"label": "Privileged insider",
"description": "Holds an operator role, custodies funds, receives keys or plaintext by design, or delivers the client: upgrade admin, custodian, view key holder, enclave operator, association set provider, hosted prover, registry, frontend host.",
"examples": "A compliance backdoor key, a DAO with an upgrade key, a KMS committee, an ASP operator, a custodial bridge."
},
{
"id": "futureAdversary",
"label": "Future adversary",
"description": "Harvest now, decrypt later. Holds every byte ever written onchain plus any retained logs, and breaks all public-key cryptography, by quantum computer or new mathematics: elliptic curves, pairings, RSA, lattices and isogenies. Hashes, Poseidon included, and symmetric ciphers survive.",
"description": "Harvest now, decrypt later. Holds every byte ever published and runs the known quantum attacks: elliptic curves, pairings and RSA fall. Hashes, symmetric ciphers and post-quantum schemes stand until an attack on them is known.",
"examples": "An intelligence agency archiving chain data today, then anyone once a break is public."
}
],
"fields": [
{
"id": "sender",
"label": "Sender",
"subject": "Sender",
"promiseLabel": "Sender privacy",
"description": "The Ethereum address that funds entered from, or that initiated a transfer."
},
{
"id": "recipient",
"label": "Recipient",
"subject": "Recipient",
"promiseLabel": "Recipient privacy",
"description": "Who receives the funds: the address they exit to, the receiver of a transfer, or whoever controls a one-time receiving address."
},
{
"id": "amount",
"label": "Amount",
"subject": "Amounts",
"promiseLabel": "Amount privacy",
"description": "The value moved."
},
{
"id": "asset",
"label": "Asset",
"subject": "Asset",
"promiseLabel": "Asset privacy",
"description": "Which token is moved."
},
{
"id": "linkage",
"label": "Link",
"subject": "Link",
"promiseLabel": "Link privacy",
"description": "Whether the entry and exit of the same funds, or sender and recipient of the same transfer, can be tied together."
}
],
"cells": {
"publicObserver": {
"sentiment": "good",
"exposureShort": "Everything inside the pool is hidden, including which shield funds which unshield.",
"exposureContinued": "Shields and unshields show address, token and amount. DeFi bundles unshield to the adapter in cleartext.",
"advice": "Exit through a broadcaster, so none of the user's wallets pay gas for the receiving address.",
"interior": {
"sender": "private",
"recipient": "private",
"amount": {
"verdict": "atRisk",
"note": "Public in DeFi bundles."
},
"asset": {
"verdict": "atRisk",
"note": "Public in DeFi bundles."
},
"linkage": "private"
},
"sources": [
{
"contract": "RailgunSmartWallet",
"title": "Shield and unshield"
},
{
"contract": "RelayAdapt",
"title": "DeFi bundles"
}
],
"id": "publicObserver",
"value": "Link private",
"alsoExposed": []
},
"chainAnalyst": {
"sentiment": "good",
"exposureShort": "The candidates for an unshield are the shields of the same token.",
"exposureContinued": "In-pool transfers break a one-to-one match, while timing and exact amounts narrow it.",
"advice": "Withdraw common amounts rather than everything at once. Wait before exiting and pick a different time of day than the deposit. Exit to a fresh address every time and spend from it with a different wallet than the one that deposited.",
"interior": {
"sender": "private",
"recipient": "private",
"amount": {
"verdict": "atRisk",
"note": "Public in DeFi bundles."
},
"asset": {
"verdict": "atRisk",
"note": "Public in DeFi bundles."
},
"linkage": "private"
},
"sources": [
{
"title": "A Tattered Cloak of Invisibility (arXiv:2606.25926)",
"url": "https://arxiv.org/abs/2606.25926"
},
{
"title": "The Anonymity Gap (arXiv:2608.22987)",
"url": "https://arxiv.org/abs/2608.22987"
}
],
"id": "chainAnalyst",
"value": "Link private",
"alsoExposed": []
},
"networkObserver": {
"sentiment": "good",
"exposureShort": "RailOxide sends all traffic over built-in Tor, broadcaster messages included, and finds the user's notes by decrypting every note locally.",
"exposureContinued": "All traffic shares one Tor session, so the public RPCs it picks at random see the user's public addresses, shields and the gas estimate of each private transaction from one exit. The user's own node as its RPC keeps these from third parties.",
"advice": "Use RailOxide, the wallet these ratings assume, and set the user's own node as its Ethereum RPC.",
"interior": {
"sender": "private",
"recipient": "private",
"amount": {
"verdict": "atRisk",
"note": "Public in DeFi bundles."
},
"asset": {
"verdict": "atRisk",
"note": "Public in DeFi bundles."
},
"linkage": {
"verdict": "atRisk",
"note": "Private only with the user's own node as RPC, over the default Tor."
}
},
"sources": [
{
"title": "Built-in Tor is the default",
"url": "https://github.com/triamazikamno/railoxide/blob/8773f4ecb00c6ac7cf164ba1f989eb77dd4b0ec5/crates/wallet-ops/src/settings/network_chains.rs#L10-L15"
},
{
"title": "Every stream uses one Tor session",
"url": "https://github.com/triamazikamno/railoxide/blob/8773f4ecb00c6ac7cf164ba1f989eb77dd4b0ec5/crates/wallet-ops/src/http.rs#L1549-L1559"
},
{
"title": "A custom RPC list replaces the public pool",
"url": "https://github.com/triamazikamno/railoxide/blob/8773f4ecb00c6ac7cf164ba1f989eb77dd4b0ec5/crates/wallet-ops/src/settings/effective.rs#L263-L277"
}
],
"id": "networkObserver",
"value": "Link private",
"alsoExposed": []
},
"privilegedInsider": {
"sentiment": "good",
"exposureShort": "Only the user holds viewing keys, and DAO upgrades wait 7 days.",
"exposureContinued": "PPoI list providers can refuse a shield, which leaves a self-broadcast exit. RailOxide builds PPoIs from a local copy of the lists. After each transaction it sends the PPoI node only that transaction's new notes with their proofs.",
"advice": "Watch governance proposals and unshield before an upgrade the user rejects executes.",
"interior": {
"sender": "private",
"recipient": "private",
"amount": {
"verdict": "atRisk",
"note": "Public in DeFi bundles."
},
"asset": {
"verdict": "atRisk",
"note": "Public in DeFi bundles."
},
"linkage": {
"verdict": "atRisk",
"note": "Private only with a wallet that builds PPoIs locally, like RailOxide."
}
},
"sources": [
{
"section": "upgrades-and-governance"
},
{
"title": "RailOxide builds PPoIs locally",
"url": "https://github.com/triamazikamno/railoxide/blob/8773f4ecb00c6ac7cf164ba1f989eb77dd4b0ec5/crates/wallet-ops/src/poi_contexts.rs#L116-L150"
}
],
"id": "privilegedInsider",
"value": "Link private",
"alsoExposed": []
},
"futureAdversary": {
"sentiment": "warning",
"exposureShort": "Notes are encrypted with elliptic-curve key exchange.",
"exposureContinued": "Whoever breaks elliptic-curve cryptography decrypts every note sent to a 0zk address that was ever shared, broadcaster fee notes included.",
"advice": "Share the user's 0zk address privately, with a fresh one per counterparty where possible.",
"interior": {
"sender": "atRisk",
"recipient": "atRisk",
"amount": "atRisk",
"asset": "atRisk",
"linkage": {
"verdict": "atRisk",
"note": "Private only while the user's 0zk address stays unshared."
}
},
"sources": [
{
"title": "Shared key derivation (Ed25519 ECDH)",
"url": "https://github.com/Railgun-Community/engine/blob/6e2614d53a106dd62abad91e7ce03ee4a3956138/src/utils/keys-utils.ts#L186-L224"
},
{
"title": "AES-GCM note encryption",
"url": "https://github.com/Railgun-Community/engine/blob/6e2614d53a106dd62abad91e7ce03ee4a3956138/src/utils/encryption/aes.ts#L24-L40"
}
],
"id": "futureAdversary",
"value": "Link at risk",
"alsoExposed": [
{
"field": "sender",
"exposure": "atRisk"
},
{
"field": "recipient",
"exposure": "atRisk"
}
]
}
}
},
"attributes": [
{
"id": "zk",
"label": "ZK",
"description": "Uses zero-knowledge proofs to prove private actions without revealing private data."
},
{
"id": "transfers",
"label": "Transfers",
"description": "Private transfers within the shielded pool."
},
{
"id": "defi",
"label": "DeFi",
"description": "Interop with DeFi (swaps, vaults) from within the shielded pool."
},
{
"id": "anyAmount",
"label": "Any amount",
"description": "Deposits and withdrawals can have any size."
}
],
"category": {
"id": "shieldedLedger",
"label": "Shielded ledger",
"description": "A pool with transfers or DeFi inside. Hides who pays whom and which deposit became which withdrawal."
},
"exitWindow": {
"value": "7d",
"sentiment": "warning",
"orderHint": 604800,
"description": "DAO-approved upgrades wait 7d before execution, so users can unshield before a change they reject.",
"walkawayTest": {
"passed": true
}
},
"relayerTracking": {
"type": "railgunWaku",
"chainId": 1,
"sinceTimestamp": 1788134400
},
"reproducibility": {
"value": "Reproducible",
"sentiment": "good",
"description": "The contracts, circuits, and supporting software needed to participate in the protocol are publicly available and can be run locally."
},
"riskSummary": "## Funds can be stolen if\n1. the zk proof system is broken, allowing invalid spends or withdrawals.\n2. all [trusted setup](#trusted-setups) participants collude or leak their secrets, allowing forged proofs.\n3. the DAO passes a malicious [upgrade](#upgrades-and-governance) and users stay in the pool past its 7 days execution delay.\n
\n## Funds can be lost if\n1. a user loses the keys of their private balance.\n
\n## Privacy can be lost if\n1. a user sends transactions from their own public address (see public observer).\n2. elliptic-curve cryptography is broken, which decrypts every note sent to a 0zk address that was ever shared (see future adversary).",
"tokens": [
{
"token": {
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"iconUrl": "https://assets.coingecko.com/coins/images/2518/large/weth.png?1696503332",
"symbol": "WETH",
"decimals": 18,
"priceId": "weth",
"sinceTimestamp": 1573689600
},
"buckets": [
{
"id": "railgun-WETH",
"type": "pool",
"label": "WETH",
"address": "eth:0xFA7093CDD9EE6932B4eb2c9e1cde7CE00B1FA4b9",
"sinceTimestamp": 1651422389,
"anonymitySet": {
"minimumAmounts": [
"100000000000000000",
"10000000000000000000"
]
},
"deposit": {
"event": "0x3a5b9dc26075a3801a6ddccf95fec485bb7500a91b44cec1add984c21ee6db3b",
"extractor": "railgunShield",
"params": {
"tokenAddress": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
}
},
"withdrawal": {
"event": "0xd93cf895c7d5b2cd7dc7a098b678b3089f37d91f48d9b83a0800a91cbdf05284",
"extractor": "railgunUnshield",
"params": {
"tokenAddress": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
}
}
}
]
},
{
"token": {
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"iconUrl": "https://assets.coingecko.com/coins/images/325/large/Tether.png?1696501661",
"symbol": "USDT",
"decimals": 6,
"priceId": "tether",
"sinceTimestamp": 1573689600
},
"buckets": [
{
"id": "railgun-USDT",
"type": "pool",
"label": "USDT",
"address": "eth:0xFA7093CDD9EE6932B4eb2c9e1cde7CE00B1FA4b9",
"sinceTimestamp": 1651422389,
"anonymitySet": {
"minimumAmounts": [
"200000000",
"20000000000"
]
},
"deposit": {
"event": "0x3a5b9dc26075a3801a6ddccf95fec485bb7500a91b44cec1add984c21ee6db3b",
"extractor": "railgunShield",
"params": {
"tokenAddress": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
}
},
"withdrawal": {
"event": "0xd93cf895c7d5b2cd7dc7a098b678b3089f37d91f48d9b83a0800a91cbdf05284",
"extractor": "railgunUnshield",
"params": {
"tokenAddress": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
}
}
}
]
},
{
"token": {
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"iconUrl": "https://assets.coingecko.com/coins/images/6319/large/usdc.png?1696506694",
"symbol": "USDC",
"decimals": 6,
"priceId": "usd-coin",
"sinceTimestamp": 1573689600
},
"buckets": [
{
"id": "railgun-USDC",
"type": "pool",
"label": "USDC",
"address": "eth:0xFA7093CDD9EE6932B4eb2c9e1cde7CE00B1FA4b9",
"sinceTimestamp": 1651422389,
"anonymitySet": {
"minimumAmounts": [
"200000000",
"20000000000"
]
},
"deposit": {
"event": "0x3a5b9dc26075a3801a6ddccf95fec485bb7500a91b44cec1add984c21ee6db3b",
"extractor": "railgunShield",
"params": {
"tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
}
},
"withdrawal": {
"event": "0xd93cf895c7d5b2cd7dc7a098b678b3089f37d91f48d9b83a0800a91cbdf05284",
"extractor": "railgunUnshield",
"params": {
"tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
}
}
}
]
},
{
"token": {
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"iconUrl": "https://assets.coingecko.com/coins/images/9956/large/Badge_Dai.png?1696509996",
"symbol": "DAI",
"decimals": 18,
"priceId": "dai",
"sinceTimestamp": 1574121600
},
"buckets": [
{
"id": "railgun-DAI",
"type": "pool",
"label": "DAI",
"address": "eth:0xFA7093CDD9EE6932B4eb2c9e1cde7CE00B1FA4b9",
"sinceTimestamp": 1651422389,
"anonymitySet": {
"minimumAmounts": [
"200000000000000000000",
"20000000000000000000000"
]
},
"deposit": {
"event": "0x3a5b9dc26075a3801a6ddccf95fec485bb7500a91b44cec1add984c21ee6db3b",
"extractor": "railgunShield",
"params": {
"tokenAddress": "0x6B175474E89094C44Da98b954EedeAC495271d0F"
}
},
"withdrawal": {
"event": "0xd93cf895c7d5b2cd7dc7a098b678b3089f37d91f48d9b83a0800a91cbdf05284",
"extractor": "railgunUnshield",
"params": {
"tokenAddress": "0x6B175474E89094C44Da98b954EedeAC495271d0F"
}
}
}
]
},
{
"token": {
"address": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
"iconUrl": "https://assets.coingecko.com/coins/images/7598/large/wrapped_bitcoin_wbtc.png?1696507857",
"symbol": "WBTC",
"decimals": 8,
"priceId": "wrapped-bitcoin",
"sinceTimestamp": 1573689600
},
"buckets": [
{
"id": "railgun-WBTC",
"type": "pool",
"label": "WBTC",
"address": "eth:0xFA7093CDD9EE6932B4eb2c9e1cde7CE00B1FA4b9",
"sinceTimestamp": 1651422389,
"deposit": {
"event": "0x3a5b9dc26075a3801a6ddccf95fec485bb7500a91b44cec1add984c21ee6db3b",
"extractor": "railgunShield",
"params": {
"tokenAddress": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
}
},
"withdrawal": {
"event": "0xd93cf895c7d5b2cd7dc7a098b678b3089f37d91f48d9b83a0800a91cbdf05284",
"extractor": "railgunUnshield",
"params": {
"tokenAddress": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
}
}
}
]
},
{
"token": {
"address": "0x85F17Cf997934a597031b2E18a9aB6ebD4B9f6a4",
"iconUrl": "https://coin-images.coingecko.com/coins/images/71681/large/near.png?1768905174",
"symbol": "NEAR",
"decimals": 24,
"priceId": "rainbow-bridged-near-ethereum",
"sinceTimestamp": 1768867200
},
"buckets": [
{
"id": "railgun-NEAR",
"type": "pool",
"label": "NEAR",
"address": "eth:0xFA7093CDD9EE6932B4eb2c9e1cde7CE00B1FA4b9",
"sinceTimestamp": 1768867200,
"deposit": {
"event": "0x3a5b9dc26075a3801a6ddccf95fec485bb7500a91b44cec1add984c21ee6db3b",
"extractor": "railgunShield",
"params": {
"tokenAddress": "0x85F17Cf997934a597031b2E18a9aB6ebD4B9f6a4"
}
},
"withdrawal": {
"event": "0xd93cf895c7d5b2cd7dc7a098b678b3089f37d91f48d9b83a0800a91cbdf05284",
"extractor": "railgunUnshield",
"params": {
"tokenAddress": "0x85F17Cf997934a597031b2E18a9aB6ebD4B9f6a4"
}
}
}
]
},
{
"token": {
"address": "0x6f40d4A6237C257fff2dB00FA0510DeEECd303eb",
"iconUrl": "https://coin-images.coingecko.com/coins/images/14688/large/Logo_1_%28brighter%29.png?1734430693",
"symbol": "FLUID",
"decimals": 18,
"priceId": "instadapp",
"sinceTimestamp": 1623801600
},
"buckets": [
{
"id": "railgun-FLUID",
"type": "pool",
"label": "FLUID",
"address": "eth:0xFA7093CDD9EE6932B4eb2c9e1cde7CE00B1FA4b9",
"sinceTimestamp": 1651422389,
"deposit": {
"event": "0x3a5b9dc26075a3801a6ddccf95fec485bb7500a91b44cec1add984c21ee6db3b",
"extractor": "railgunShield",
"params": {
"tokenAddress": "0x6f40d4A6237C257fff2dB00FA0510DeEECd303eb"
}
},
"withdrawal": {
"event": "0xd93cf895c7d5b2cd7dc7a098b678b3089f37d91f48d9b83a0800a91cbdf05284",
"extractor": "railgunUnshield",
"params": {
"tokenAddress": "0x6f40d4A6237C257fff2dB00FA0510DeEECd303eb"
}
}
}
]
},
{
"token": {
"address": "0xe76C6c83af64e4C60245D8C7dE953DF673a7A33D",
"iconUrl": "https://coin-images.coingecko.com/coins/images/16840/large/railgun.jpeg?1696516407",
"symbol": "RAIL",
"decimals": 18,
"priceId": "railgun",
"sinceTimestamp": 1625270400
},
"buckets": [
{
"id": "railgun-RAIL",
"type": "pool",
"label": "RAIL",
"address": "eth:0xFA7093CDD9EE6932B4eb2c9e1cde7CE00B1FA4b9",
"sinceTimestamp": 1651422389,
"deposit": {
"event": "0x3a5b9dc26075a3801a6ddccf95fec485bb7500a91b44cec1add984c21ee6db3b",
"extractor": "railgunShield",
"params": {
"tokenAddress": "0xe76C6c83af64e4C60245D8C7dE953DF673a7A33D"
}
},
"withdrawal": {
"event": "0xd93cf895c7d5b2cd7dc7a098b678b3089f37d91f48d9b83a0800a91cbdf05284",
"extractor": "railgunUnshield",
"params": {
"tokenAddress": "0xe76C6c83af64e4C60245D8C7dE953DF673a7A33D"
}
}
}
]
}
],
"trackedOn": [
"ethereum"
],
"upgradesAndGovernance": {
"content": "RAIL stakers govern Railgun through a DAO. It can upgrade the core contract and its circuits, which changes the rules for every shielded token. It can also block tokens from new shields, mint RAIL and manage governance rewards. [Governance docs](https://docs.railgun.org/wiki/rail-token/protocol-governance).",
"governanceInfo": {
"upgrades": {
"Normal upgrade path": "Create a proposal with an IPFS link and onchain calldata in the [Voting contract](https://etherscan.io/address/0xc480F68A3dcC3EdD82134FAB45C14A0FcF1dA3CC) → collect **500.00 K RAIL** sponsorship within 1mo → wait 2d → cast Yay votes within 5d and Nay votes within 6d → pass with a simple majority and **2.00 M RAIL** quorum → wait 7d → permissionless execution through the Delegator within 14d.",
"Exit window": "**7d** — a passed proposal must wait this long before it can be executed, giving users time to unshield funds."
},
"tokenGovernance": {
"Governance token": "`RAIL` 1 token = 1 vote, delegated. Total supply: **60.00 M RAIL**, DAO-owned treasury (unavailable for voting): **2.30 M RAIL**, staked for voting: **41.61 M RAIL**, the rest is circulating supply.",
"Stake lock": "Unstaking has **1mo** delay.",
"Voting venue": "[Voting contract](https://etherscan.io/address/0xc480F68A3dcC3EdD82134FAB45C14A0FcF1dA3CC) on Ethereum. Proposal text is distributed over IPFS, its CID is available as a parameter of `createPropsal()` call on the voting contract.",
"Proposal threshold": "**No threshold to create a proposal.** A proposal must receive sponsorship from **500.00 K RAIL** stake within 1mo.",
"Quorum": "**2.00 M RAIL**, with a simple majority required for acceptance.",
"Execution model": "**Onchain calldata · Permissionless execution through the Delegator.** A passed proposal waits 7d, after which anyone can execute it through the [Delegator contract](https://etherscan.io/address/0xB6d513f6222Ee92Fff975E901bd792E2513fB53B) within 14d."
}
}
}
}
+1 -1
+1 -1
{
"adversaries": {
"promise": {
"protects": "linkage",
"text": "Hides amounts, senders and the link between deposit and withdrawal inside the pool. The first payment to each new contact is public."
},
"adversaries": [
{
"id": "publicObserver",
"label": "Public observer",
"description": "Everyone with a block explorer and some basic tools. Sees every public onchain event, but does no correlation beyond following links.",
"examples": "A curious counterparty, an employer, a journalist."
},
{
"id": "chainAnalyst",
"label": "Chain analyst",
"description": "Scrapes all public data and correlates it: timing, amounts, gas and wallet fingerprints, address clusters.",
"examples": "Chain analytics firms, ZachXBT, data brokers."
},
{
"id": "networkObserver",
"label": "Network observer",
"description": "Sits between the user and the services and sees traffic only: ISPs, VPNs, Tor exits, public RPCs and relayers. Learns IP addresses, timing, fingerprints and ciphertext. Services the operator runs count as the insider.",
"examples": "Infura or Alchemy, a Tornado relayer, a wallet vendor selling telemetry, Google captcha or analytics in the dapp frontend."
},
{
"id": "privilegedInsider",
"label": "Privileged insider",
"description": "Holds an operator role, custodies funds, receives keys or plaintext by design, or delivers the client: upgrade admin, custodian, view key holder, enclave operator, association set provider, hosted prover, registry, frontend host.",
"examples": "A compliance backdoor key, a DAO with an upgrade key, a KMS committee, an ASP operator, a custodial bridge."
},
{
"id": "futureAdversary",
"label": "Future adversary",
"description": "Harvest now, decrypt later. Holds every byte ever written onchain plus any retained logs, and breaks all public-key cryptography, by quantum computer or new mathematics: elliptic curves, pairings, RSA, lattices and isogenies. Hashes, Poseidon included, and symmetric ciphers survive.",
"description": "Harvest now, decrypt later. Holds every byte ever published and runs the known quantum attacks: elliptic curves, pairings and RSA fall. Hashes, symmetric ciphers and post-quantum schemes stand until an attack on them is known.",
"examples": "An intelligence agency archiving chain data today, then anyone once a break is public."
}
],
"fields": [
{
"id": "sender",
"label": "Sender",
"subject": "Sender",
"promiseLabel": "Sender privacy",
"description": "The Ethereum address that funds entered from, or that initiated a transfer."
},
{
"id": "recipient",
"label": "Recipient",
"subject": "Recipient",
"promiseLabel": "Recipient privacy",
"description": "Who receives the funds: the address they exit to, the receiver of a transfer, or whoever controls a one-time receiving address."
},
{
"id": "amount",
"label": "Amount",
"subject": "Amounts",
"promiseLabel": "Amount privacy",
"description": "The value moved."
},
{
"id": "asset",
"label": "Asset",
"subject": "Asset",
"promiseLabel": "Asset privacy",
"description": "Which token is moved."
},
{
"id": "linkage",
"label": "Link",
"subject": "Link",
"promiseLabel": "Link privacy",
"description": "Whether the entry and exit of the same funds, or sender and recipient of the same transfer, can be tied together."
}
],
"cells": {
"publicObserver": {
"sentiment": "warning",
"exposureShort": "Transfers inside the pool are encrypted, but the first payment to each new contact writes the recipient's address in cleartext.",
"exposureContinued": "Deposits and withdrawals show address, token and amount. The fee payment names the token the user pays it in, and DeFi actions name their target contract. A new account must be funded publicly before it can receive privately.",
"advice": "Submit every pool action through a paymaster and pay its fee in the most common token. Treat the first payment to a new contact, and any DeFi action, as public.",
"interior": {
"sender": "private",
"recipient": {
"verdict": "exposed",
"note": "Opening a channel writes the recipient address in cleartext; later transfers do not."
},
"amount": "private",
"asset": {
"verdict": "atRisk",
"note": "The fee payment names the token; DeFi actions name the target contract."
},
"linkage": "private"
},
"sources": [
{
"title": "PrivacyPool contract on Voyager",
"url": "https://voyager.online/contract/0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a"
},
{
"title": "Channel opening carries the recipient address",
"url": "https://github.com/starkware-libs/starknet-privacy/blob/f9256c5e37682d37437e69a795ddd51d924c9b97/packages/privacy/src/actions.cairo#L329-L334"
},
{
"title": "Deposit and withdrawal events carry address, token and amount",
"url": "https://github.com/starkware-libs/starknet-privacy/blob/f9256c5e37682d37437e69a795ddd51d924c9b97/packages/privacy/src/events.cairo#L17-L40"
}
],
"id": "publicObserver",
"value": "Link at risk",
"alsoExposed": []
},
"chainAnalyst": {
"sentiment": "warning",
"exposureShort": "The set of active users is small and split further by token and by fee token.",
"exposureContinued": "A channel opened in the same transaction as a deposit ties the two together, and most withdrawal addresses have also deposited. Paying gas from the user's wallet instead of a paymaster exposes its fingerprint, account implementation and fee habits, even from a fresh address.",
"advice": "Open channels in a transaction without a deposit, pay fees in the most common token, and withdraw uneven amounts that match no deposit. Wait before exiting and pick a different time of day than the deposit. Exit to a fresh address every time and spend from it with a different wallet than the one that deposited.",
"interior": {
"sender": {
"verdict": "atRisk",
"note": "A channel opened in the same transaction as a deposit names the depositor."
},
"recipient": "exposed",
"amount": "private",
"asset": "atRisk",
"linkage": {
"verdict": "atRisk",
"note": "Most withdrawal addresses have also deposited, which pairs the two ends."
}
},
"sources": [
{
"title": "PrivacyPool contract on Voyager",
"url": "https://voyager.online/contract/0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a"
},
{
"title": "Deposit and withdrawal events carry address, token and amount",
"url": "https://github.com/starkware-libs/starknet-privacy/blob/f9256c5e37682d37437e69a795ddd51d924c9b97/packages/privacy/src/events.cairo#L17-L40"
}
],
"id": "chainAnalyst",
"value": "Link at risk",
"alsoExposed": [
{
"field": "sender",
"exposure": "atRisk"
}
]
},
"networkObserver": {
"sentiment": "warning",
"exposureShort": "Ready and Xverse are closed source, so what they send to third parties is up to their makers and can change at any time.",
"exposureContinued": "Today both wallets send each action to their own servers for proving and note discovery. The paymaster receives the finished transaction with its proof before broadcast, and how much of the private execution the proof reveals is not established.",
"advice": "Use a client built on the open SDK with the user's own prover and note discovery, and turn on its oblivious relay.",
"interior": {
"sender": "unverifiable",
"recipient": "unverifiable",
"amount": "unverifiable",
"asset": "atRisk",
"linkage": "unverifiable"
},
"sources": [
{
"title": "Ready extension (proving and discovery on Ready servers)",
"url": "https://chromewebstore.google.com/detail/dlcobpjiigpikoobohmabehhmhfoodbb"
},
{
"title": "Xverse extension (proving and discovery on Xverse servers)",
"url": "https://chromewebstore.google.com/detail/idnnbdplmphpflfnlkomgpfbpcgelopg"
},
{
"title": "The SDK takes prover and discovery endpoints from the client",
"url": "https://github.com/starkware-libs/starknet-privacy/blob/fcc7c90f544ceb08621c32616bde29f1fdcbeb54/sdk/src/factory.ts#L45-L62"
},
{
"title": "Oblivious relay is an option of the proving client",
"url": "https://github.com/starkware-libs/starknet-privacy/blob/fcc7c90f544ceb08621c32616bde29f1fdcbeb54/sdk/src/internal/proving-service-provider.ts#L73-L80"
}
],
"id": "networkObserver",
"value": "Link at risk",
"alsoExposed": [
{
"field": "sender",
"exposure": "unverifiable"
},
{
"field": "amount",
"exposure": "unverifiable"
}
]
},
"privilegedInsider": {
"sentiment": "bad",
"exposureShort": "Every user's viewing key is escrowed onchain, encrypted to one auditor key that a role holder can replace at any time with no delay.",
"exposureContinued": "The wallet's prover receives the user's viewing key with every action, and for most Ready accounts Ready's servers create that key. Ready's servers also learn every recipient the wallet checks for registration. StarkWare's sequencer alone checks the client proofs, which are not zero-knowledge by default. Every deposit needs a fresh signature from the holder of the screener key, who can block any depositor.",
"interior": {
"sender": "exposed",
"recipient": "exposed",
"amount": "exposed",
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "Viewing key escrowed to the auditor key onchain",
"url": "https://github.com/starkware-libs/starknet-privacy/blob/f9256c5e37682d37437e69a795ddd51d924c9b97/packages/privacy/src/events.cairo#L5-L13"
},
{
"title": "Proving request carries the viewing key",
"url": "https://github.com/starkware-libs/starknet-privacy/blob/fcc7c90f544ceb08621c32616bde29f1fdcbeb54/sdk/src/internal/proof-invocation-factory.ts#L132-L136"
},
{
"title": "Deposits require a screening attestation",
"url": "https://github.com/starkware-libs/starknet-privacy/blob/f9256c5e37682d37437e69a795ddd51d924c9b97/packages/privacy/src/interface.cairo#L530-L545"
},
{
"title": "Stwo Cairo is not zero-knowledge by default",
"url": "https://github.com/starkware-libs/stwo-cairo/blob/2b1fb4ded5496fb2db4e8261cd5ee5ef6b710839/README.md#security-model"
}
],
"id": "privilegedInsider",
"value": "Link exposed",
"alsoExposed": [
{
"field": "sender",
"exposure": "exposed"
},
{
"field": "amount",
"exposure": "exposed"
},
{
"field": "asset",
"exposure": "exposed"
}
]
},
"futureAdversary": {
"sentiment": "bad",
"exposureShort": "The proofs rest only on hashes, the encryption on elliptic curves.",
"exposureContinued": "Channel keys, note contents and the auditor escrow all use this encryption. Whoever breaks elliptic-curve cryptography recovers the auditor key from its onchain public key, and with it every escrowed viewing key and the whole history.",
"interior": {
"sender": "exposed",
"recipient": "exposed",
"amount": "exposed",
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "Stark-curve ECDH encryption of channel and note data",
"url": "https://github.com/starkware-libs/starknet-privacy/blob/fcc7c90f544ceb08621c32616bde29f1fdcbeb54/sdk/src/utils/encryptions.ts"
},
{
"title": "Viewing key escrowed under the onchain auditor public key",
"url": "https://github.com/starkware-libs/starknet-privacy/blob/f9256c5e37682d37437e69a795ddd51d924c9b97/packages/privacy/src/events.cairo#L5-L13"
},
{
"title": "Auditor public key in pool storage",
"url": "https://voyager.online/contract/0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a"
}
],
"id": "futureAdversary",
"value": "Link exposed",
"alsoExposed": [
{
"field": "sender",
"exposure": "exposed"
},
{
"field": "amount",
"exposure": "exposed"
},
{
"field": "asset",
"exposure": "exposed"
}
]
}
}
},
"attributes": [
{
"id": "zk",
"label": "ZK",
"description": "Uses zero-knowledge proofs to prove private actions without revealing private data."
},
{
"id": "transfers",
"label": "Transfers",
"description": "Private transfers within the shielded pool."
},
{
"id": "defi",
"label": "DeFi",
"description": "Interop with DeFi (swaps, vaults) from within the shielded pool."
},
{
"id": "anyAmount",
"label": "Any amount",
"description": "Deposits and withdrawals can have any size."
}
],
"category": {
"id": "shieldedLedger",
"label": "Shielded ledger",
"description": "A pool with transfers or DeFi inside. Hides who pays whom and which deposit became which withdrawal."
},
"exitWindow": {
"value": "None",
"sentiment": "bad",
"orderHint": 0,
"description": "The pool implementation is immediately upgradeable, so users have no delay to withdraw before a malicious upgrade can take effect.",
"walkawayTest": {
"passed": false,
"reason": "Although the full software stack needed to generate proofs and exit is published and self-hostable, STRK-20 heavily relies on the permissioned Starknet sequencer: it alone verifies client proofs and must include pool transactions, so users cannot exit without its cooperation."
}
},
"reproducibility": {
"value": "Partially reproducible",
"sentiment": "warning",
"description": "The pool contract, SDK, discovery service and prover are open source. The deployed pool runs a version without a release tag, which has not been rebuilt from source, and the wallets are closed."
},
"riskSummary": "## Funds can be stolen if\n1. the proof system or virtual Starknet execution model is broken, allowing invalid actions.\n2. the Starknet sequencer includes a transaction with fabricated proof facts.\n3. a multisig deploys a malicious pool upgrade, which takes effect without delay.\n4. an external DeFi helper or target protocol invoked by the user mishandles assets.\n
\n## Funds can be lost if\n1. a user loses the Starknet account key or viewing key required to spend their notes.\n2. the pool is paused or upgraded so that valid actions fail.\n
\n## Privacy can be lost if\n1. the holder of the auditor key decrypts users' viewing keys, which exposes their whole history (see privileged insider).\n2. the wallet's prover or note discovery service, which receives the viewing key with every action, leaks or keeps it (see privileged insider).\n3. a first payment to a new contact, a channel opened beside a deposit or a unique amount links activity (see public observer, chain analyst).\n4. elliptic-curve cryptography is broken, which opens the auditor key and with it every user's history (see future adversary).",
"tokens": [
{
"token": {
"address": "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
"iconUrl": "https://assets.coingecko.com/coins/images/26433/large/starknet.png?1696525507",
"symbol": "STRK",
"decimals": 18,
"priceId": "starknet",
"sinceTimestamp": 1776679728
},
"buckets": [
{
"id": "strk20-STRK",
"type": "pool",
"label": "STRK pool",
"address": {
"chain": "starknet",
"address": "0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a"
},
"sinceTimestamp": 1776679728,
"anonymitySet": {
"minimumAmounts": [
"5000000000000000000000",
"500000000000000000000000"
]
},
"deposit": {
"event": "0x9149d2123147c5f43d258257fef0b7b969db78269369ebcf5ebb9eef8592f2",
"extractor": "strk20Deposit",
"params": {
"tokenAddress": "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d"
}
},
"withdrawal": {
"event": "0x2eed7e29b3502a726faf503ac4316b7101f3da813654e8df02c13449e03da8",
"extractor": "strk20Withdrawal",
"params": {
"tokenAddress": "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d"
}
}
}
]
},
{
"token": {
"address": "0x033068f6539f8e6e6b131e6b2b814e6c34a5224bc66947c47dab9dfee93b35fb",
"iconUrl": "https://assets.coingecko.com/coins/images/6319/large/usdc.png?1696501661",
"symbol": "USDC",
"decimals": 6,
"priceId": "usd-coin",
"sinceTimestamp": 1776679728
},
"buckets": [
{
"id": "strk20-USDC",
"type": "pool",
"label": "USDC pool",
"address": {
"chain": "starknet",
"address": "0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a"
},
"sinceTimestamp": 1776679728,
"anonymitySet": {
"minimumAmounts": [
"200000000",
"20000000000"
]
},
"deposit": {
"event": "0x9149d2123147c5f43d258257fef0b7b969db78269369ebcf5ebb9eef8592f2",
"extractor": "strk20Deposit",
"params": {
"tokenAddress": "0x033068f6539f8e6e6b131e6b2b814e6c34a5224bc66947c47dab9dfee93b35fb"
}
},
"withdrawal": {
"event": "0x2eed7e29b3502a726faf503ac4316b7101f3da813654e8df02c13449e03da8",
"extractor": "strk20Withdrawal",
"params": {
"tokenAddress": "0x033068f6539f8e6e6b131e6b2b814e6c34a5224bc66947c47dab9dfee93b35fb"
}
}
}
]
},
{
"token": {
"address": "0x0787150e306e6eae6e3f79dea881770e8bbff2c1b8eb490f969669ee945b3135",
"iconUrl": "https://coin-images.coingecko.com/coins/images/102173511/large/strkBTC_Logo.png?1779888214",
"symbol": "strkBTC",
"decimals": 8,
"priceId": "strkbtc",
"sinceTimestamp": 1777893725
},
"buckets": [
{
"id": "strk20-strkBTC",
"type": "pool",
"label": "strkBTC pool",
"address": {
"chain": "starknet",
"address": "0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a"
},
"sinceTimestamp": 1777893725,
"anonymitySet": {
"minimumAmounts": [
"250000",
"25000000"
]
},
"deposit": {
"event": "0x9149d2123147c5f43d258257fef0b7b969db78269369ebcf5ebb9eef8592f2",
"extractor": "strk20Deposit",
"params": {
"tokenAddress": "0x0787150e306e6eae6e3f79dea881770e8bbff2c1b8eb490f969669ee945b3135"
}
},
"withdrawal": {
"event": "0x2eed7e29b3502a726faf503ac4316b7101f3da813654e8df02c13449e03da8",
"extractor": "strk20Withdrawal",
"params": {
"tokenAddress": "0x0787150e306e6eae6e3f79dea881770e8bbff2c1b8eb490f969669ee945b3135"
}
}
}
]
},
{
"token": {
"address": "0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac",
"iconUrl": "https://assets.coingecko.com/coins/images/7598/large/wrapped_bitcoin_wbtc.png?1696507857",
"symbol": "WBTC",
"decimals": 8,
"priceId": "wrapped-bitcoin",
"sinceTimestamp": 1776679728
},
"buckets": [
{
"id": "strk20-WBTC",
"type": "pool",
"label": "WBTC pool",
"address": {
"chain": "starknet",
"address": "0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a"
},
"sinceTimestamp": 1776679728,
"deposit": {
"event": "0x9149d2123147c5f43d258257fef0b7b969db78269369ebcf5ebb9eef8592f2",
"extractor": "strk20Deposit",
"params": {
"tokenAddress": "0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac"
}
},
"withdrawal": {
"event": "0x2eed7e29b3502a726faf503ac4316b7101f3da813654e8df02c13449e03da8",
"extractor": "strk20Withdrawal",
"params": {
"tokenAddress": "0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac"
}
}
}
]
},
{
"token": {
"address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
"iconUrl": "https://assets.coingecko.com/coins/images/279/large/ethereum.png?1595348880",
"symbol": "ETH",
"decimals": 18,
"priceId": "ethereum",
"sinceTimestamp": 1776679728
},
"buckets": [
{
"id": "strk20-ETH",
"type": "pool",
"label": "ETH pool",
"address": {
"chain": "starknet",
"address": "0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a"
},
"sinceTimestamp": 1776679728,
"anonymitySet": {
"minimumAmounts": [
"100000000000000000",
"10000000000000000000"
]
},
"deposit": {
"event": "0x9149d2123147c5f43d258257fef0b7b969db78269369ebcf5ebb9eef8592f2",
"extractor": "strk20Deposit",
"params": {
"tokenAddress": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
}
},
"withdrawal": {
"event": "0x2eed7e29b3502a726faf503ac4316b7101f3da813654e8df02c13449e03da8",
"extractor": "strk20Withdrawal",
"params": {
"tokenAddress": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
}
}
}
]
},
{
"token": {
"address": "0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a",
"iconUrl": "https://assets.coingecko.com/coins/images/54172/standard/logo200x200.png?1738561141",
"symbol": "XSTRK",
"decimals": 18,
"priceId": "endur-fi-staked-strk",
"sinceTimestamp": 1776679728
},
"buckets": [
{
"id": "strk20-XSTRK",
"type": "pool",
"label": "XSTRK pool",
"address": {
"chain": "starknet",
"address": "0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a"
},
"sinceTimestamp": 1776679728,
"deposit": {
"event": "0x9149d2123147c5f43d258257fef0b7b969db78269369ebcf5ebb9eef8592f2",
"extractor": "strk20Deposit",
"params": {
"tokenAddress": "0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
}
},
"withdrawal": {
"event": "0x2eed7e29b3502a726faf503ac4316b7101f3da813654e8df02c13449e03da8",
"extractor": "strk20Withdrawal",
"params": {
"tokenAddress": "0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
}
}
}
]
},
{
"token": {
"address": "0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8",
"iconUrl": "https://assets.coingecko.com/coins/images/325/large/Tether.png?1696501661",
"decimals": 6,
"symbol": "USDT",
"priceId": "tether",
"sinceTimestamp": 1776679728
},
"buckets": [
{
"id": "strk20-USDT",
"type": "pool",
"label": "USDT pool",
"address": {
"chain": "starknet",
"address": "0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a"
},
"sinceTimestamp": 1776679728,
"anonymitySet": {
"minimumAmounts": [
"200000000",
"20000000000"
]
},
"deposit": {
"event": "0x9149d2123147c5f43d258257fef0b7b969db78269369ebcf5ebb9eef8592f2",
"extractor": "strk20Deposit",
"params": {
"tokenAddress": "0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"
}
},
"withdrawal": {
"event": "0x2eed7e29b3502a726faf503ac4316b7101f3da813654e8df02c13449e03da8",
"extractor": "strk20Withdrawal",
"params": {
"tokenAddress": "0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"
}
}
}
]
}
],
"trackedOn": [
"starknet"
],
"upgradesAndGovernance": {
"content": "The pool is an upgradeable contract with StarkWare's role system. One multisig holds the governance, security and upgrade roles and can replace the pool's code at once, as it did on 2026-09-23. A second multisig sets the fee, the fee collector, the proof validity window and which DeFi helpers need screening. It also owns a delayed executor that holds the upgrade role behind a one-day delay but has not been used. The security governor role, held by the first multisig, can replace the auditor and screener keys at once. Pausing needs a role nobody holds today, which the first multisig can grant."
},
"zkCatalogId": "stwo"
}
+1 -1
+1 -1
{
"adversaries": {
"promise": {
"protects": "linkage",
"text": "Hides which deposit funds which withdrawal. Everything else is public."
},
"adversaries": [
{
"id": "publicObserver",
"label": "Public observer",
"description": "Everyone with a block explorer and some basic tools. Sees every public onchain event, but does no correlation beyond following links.",
"examples": "A curious counterparty, an employer, a journalist."
},
{
"id": "chainAnalyst",
"label": "Chain analyst",
"description": "Scrapes all public data and correlates it: timing, amounts, gas and wallet fingerprints, address clusters.",
"examples": "Chain analytics firms, ZachXBT, data brokers."
},
{
"id": "networkObserver",
"label": "Network observer",
"description": "Sits between the user and the services and sees traffic only: ISPs, VPNs, Tor exits, public RPCs and relayers. Learns IP addresses, timing, fingerprints and ciphertext. Services the operator runs count as the insider.",
"examples": "Infura or Alchemy, a Tornado relayer, a wallet vendor selling telemetry, Google captcha or analytics in the dapp frontend."
},
{
"id": "privilegedInsider",
"label": "Privileged insider",
"description": "Holds an operator role, custodies funds, receives keys or plaintext by design, or delivers the client: upgrade admin, custodian, view key holder, enclave operator, association set provider, hosted prover, registry, frontend host.",
"examples": "A compliance backdoor key, a DAO with an upgrade key, a KMS committee, an ASP operator, a custodial bridge."
},
{
"id": "futureAdversary",
"label": "Future adversary",
"description": "Harvest now, decrypt later. Holds every byte ever written onchain plus any retained logs, and breaks all public-key cryptography, by quantum computer or new mathematics: elliptic curves, pairings, RSA, lattices and isogenies. Hashes, Poseidon included, and symmetric ciphers survive.",
"description": "Harvest now, decrypt later. Holds every byte ever published and runs the known quantum attacks: elliptic curves, pairings and RSA fall. Hashes, symmetric ciphers and post-quantum schemes stand until an attack on them is known.",
"examples": "An intelligence agency archiving chain data today, then anyone once a break is public."
}
],
"fields": [
{
"id": "sender",
"label": "Sender",
"subject": "Sender",
"promiseLabel": "Sender privacy",
"description": "The Ethereum address that funds entered from, or that initiated a transfer."
},
{
"id": "recipient",
"label": "Recipient",
"subject": "Recipient",
"promiseLabel": "Recipient privacy",
"description": "Who receives the funds: the address they exit to, the receiver of a transfer, or whoever controls a one-time receiving address."
},
{
"id": "amount",
"label": "Amount",
"subject": "Amounts",
"promiseLabel": "Amount privacy",
"description": "The value moved."
},
{
"id": "asset",
"label": "Asset",
"subject": "Asset",
"promiseLabel": "Asset privacy",
"description": "Which token is moved."
},
{
"id": "linkage",
"label": "Link",
"subject": "Link",
"promiseLabel": "Link privacy",
"description": "Whether the entry and exit of the same funds, or sender and recipient of the same transfer, can be tied together."
}
],
"cells": {
"publicObserver": {
"sentiment": "good",
"exposureShort": "Each pool has one fixed amount and no in-pool transfers, so every withdrawal spends exactly one deposit.",
"advice": "Exit through a relayer, so none of the user's wallets pay gas for the receiving address.",
"sources": [
{
"contract": "Pool_1_ETH",
"title": "1 ETH pool"
},
{
"title": "Withdrawal circuit",
"url": "https://github.com/tornadocash/tornado-core/blob/a533ad9ffb62163a42d4fa9a09984c5dd4e5c41d/circuits/withdraw.circom"
}
],
"id": "publicObserver",
"value": "Link private",
"alsoExposed": []
},
"chainAnalyst": {
"sentiment": "good",
"exposureShort": "A relayed withdrawal hides among all unspent deposits of its pool, the anonymity set, which differs sharply between pools.",
"exposureContinued": "Timing, address reuse and relayer choice narrow it further. Paying gas from the user's wallet instead of a relayer exposes its fingerprint, account implementation and fee habits, even from a fresh address.",
"advice": "Use a pool with a large anonymity set. Deposit and withdraw several notes at different times, not in batches. Wait before exiting and pick a different time of day than the deposit. Exit to a fresh address every time and spend from it with a different wallet than the one that deposited.",
"sources": [
{
"contract": "Pool_1_ETH",
"title": "withdraw: any relayer, paid from the withdrawn amount"
},
{
"title": "Tutela (arXiv:2201.06811)",
"url": "https://arxiv.org/abs/2201.06811"
},
{
"title": "Blockchain is Watching You (arXiv:2005.14051)",
"url": "https://arxiv.org/abs/2005.14051"
}
],
"id": "chainAnalyst",
"value": "Link private",
"alsoExposed": []
},
"networkObserver": {
"sentiment": "good",
"exposureShort": "The app works in Tor Browser and downloads every deposit of a pool, so its services learn the pool but never the user's note.",
"exposureContinued": "Every listed relayer gets a status request, and the chosen one receives the finished withdrawal.",
"advice": "Read the chain from the user's own node, send through a public RPC over Tor, and use a popular relayer. If using a VPN instead of Tor, choose a trusted provider: it hides the user's IP from the relayer but sees it itself. Withdraw without connecting a wallet.",
"sources": [
{
"title": "Deposits fetched per pool and matched locally",
"url": "https://github.com/tornado-dao/classic-ui/blob/17c54dae9ad91bb3c6d62a7860df6cd365ab76d4/services/events.js#L90-L115"
},
{
"title": "The relayer receives only the finished withdrawal",
"url": "https://github.com/tornado-dao/classic-ui/blob/17c54dae9ad91bb3c6d62a7860df6cd365ab76d4/store/relayer.js#L430-L460"
},
{
"title": "Custom RPC setting",
"url": "https://github.com/tornado-dao/classic-ui/blob/17c54dae9ad91bb3c6d62a7860df6cd365ab76d4/components/Settings.vue#L8-L50"
},
{
"title": "Only withdrawals without a relayer need a wallet",
"url": "https://github.com/tornado-dao/classic-ui/blob/17c54dae9ad91bb3c6d62a7860df6cd365ab76d4/components/withdraw/Withdraw.vue#L224-L226"
}
],
"id": "networkObserver",
"value": "Link private",
"alsoExposed": []
},
"privilegedInsider": {
"sentiment": "good",
"exposureShort": "The pools cannot be paused, upgraded or made to reveal anything.",
"exposureContinued": "Token governance controls the app pinned on tornadocash.eth, the router's pool list and the relayer list. Every change waits at least 7 days from proposal to execution.",
"advice": "Load the app from the IPFS hash on tornadocash.eth through the user's own IPFS node. Run an inspected local build of the client instead of the hosted frontend.",
"sources": [
{
"contract": "Pool_0.1_ETH",
"title": "0.1 ETH pool (no operator)"
},
{
"section": "upgrades-and-governance"
},
{
"title": "Build recipe that recomputes the pinned app's IPFS hash",
"url": "https://github.com/tornado-dao/tornado-ipfs-ui"
}
],
"id": "privilegedInsider",
"value": "Link private",
"alsoExposed": []
},
"futureAdversary": {
"sentiment": "warning",
"exposureShort": "Commitments use a Pedersen hash on an elliptic curve.",
"exposureContinued": "Whoever breaks elliptic-curve cryptography could test whether a given deposit can fund a withdrawal, shrinking the candidate set without singling out one deposit. Notes backed up onchain are encrypted with elliptic-curve keys and become readable.",
"advice": "Keep the note on the user's device and leave the onchain backup off.",
"sources": [
{
"title": "Pedersen hash circuit (pinned circomlib fork)",
"url": "https://github.com/tornadocash/circomlib/blob/c372f14d324d57339c88451834bf2824e73bbdbc/circuits/pedersen.circom"
},
{
"title": "Commitment and nullifier hashing",
"url": "https://github.com/tornadocash/tornado-core/blob/a533ad9ffb62163a42d4fa9a09984c5dd4e5c41d/circuits/withdraw.circom"
},
{
"contract": "TornadoRouter",
"title": "Onchain note backups"
}
],
"id": "futureAdversary",
"value": "Link at risk",
"alsoExposed": []
}
}
},
"attributes": [
{
"id": "zk",
"label": "ZK",
"description": "Uses zero-knowledge proofs to prove private actions without revealing private data."
},
{
"id": "fixedAmounts",
"label": "Fixed amounts",
"description": "Pre-defined transfer amounts use distinct buckets (anonymity sets)."
}
],
"category": {
"id": "pool",
"label": "Pool",
"description": "Funds enter a shared pool and leave it later, with no actions inside. Hides which deposit became which withdrawal."
},
"exitWindow": {
"value": "Infinite",
"sentiment": "good",
"orderHint": 9007199254740991,
"description": "The core Tornado Cash contracts are immutable and have no admin upgrade path, so users can always withdraw with a valid note and proof.",
"walkawayTest": {
"passed": true
}
},
"relayerTracking": {
"type": "onchainEvents",
"sources": [
{
"address": "eth:0x12D66f87A04A9E220743712cE6d9bB1B5616B8Fc",
"sinceTimestamp": 1576523323,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0x47CE0C6eD5B0Ce3d3A51fdb1C52DC66a7c3c2936",
"sinceTimestamp": 1576534673,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0x910Cbd523D972eb0a6f4cAe4618aD62622b39DbF",
"sinceTimestamp": 1576536415,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0xA160cdAB225685dA1d56aa342Ad8841c3b53f291",
"sinceTimestamp": 1577296976,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0xD4B88Df4D29F5CedD6857912842cff3b20C8Cfa3",
"sinceTimestamp": 1576534688,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0xFD8610d20aA15b7B2E3Be39B396a1bC3516c7144",
"sinceTimestamp": 1577297383,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0x07687e702b410Fa43f4cB4Af7FA097918ffD2730",
"sinceTimestamp": 1616114822,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0x23773E65ed146A459791799d01336DB287f25334",
"sinceTimestamp": 1616115387,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0x22aaA7720ddd5388A3c0A3333430953C68f1849b",
"sinceTimestamp": 1577297782,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0x03893a7c7463AE47D46bc7f091665f1893656003",
"sinceTimestamp": 1616155055,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0x2717c5e28cf931547B621a5dddb772Ab6A35B701",
"sinceTimestamp": 1616135923,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0xD21be7248e0197Ee08E0c20D4a96DEBdaC3D20Af",
"sinceTimestamp": 1616115450,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0xd96f2B1c14Db8458374d9Aca76E26c3D18364307",
"sinceTimestamp": 1577298068,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0x4736dCf1b7A3d580672CcE6E7c65cd5cc9cFBa9D",
"sinceTimestamp": 1577298155,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0x169AD27A470D064DEDE56a2D3ff727986b15D52B",
"sinceTimestamp": 1577298900,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0x0836222F2B2B24A3F36f98668Ed8F0B38D1a872f",
"sinceTimestamp": 1577298985,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0x178169B423a011fff22B9e3F3abeA13414dDD0F1",
"sinceTimestamp": 1616134868,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0x610B717796ad172B316836AC95a2ffad065CeaB4",
"sinceTimestamp": 1616123193,
"extractor": "tornadoCashWithdrawal"
},
{
"address": "eth:0xbB93e510BbCD0B7beb5A853875f9eC60275CF498",
"sinceTimestamp": 1616135758,
"extractor": "tornadoCashWithdrawal"
}
]
},
"reproducibility": {
"value": "Reproducible",
"sentiment": "good",
"description": "The circuits, contracts, app and relayer are open source. Each app release names its commit and a build recipe for its IPFS hash, and rebuilding the current release reproduces it."
},
"riskSummary": "## Funds can be stolen if\n1. the zk proof system is broken, allowing invalid withdrawals.\n2. the [trusted setup](#trusted-setups) is compromised or all ceremony participants collude, allowing invalid withdrawals.\n3. governance pins a malicious app on tornadocash.eth, which can steal the notes, and with them the funds, of users who load it (see privileged insider).\n
\n## Funds can be lost if\n1. a user loses the note required to withdraw.\n
\n## Privacy can be lost if\n1. elliptic-curve cryptography is broken, which lets an attacker test candidate deposits for each withdrawal and read notes backed up onchain (see future adversary).",
"tokens": [
{
"token": {
"address": "0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643",
"iconUrl": "https://assets.coingecko.com/coins/images/9281/large/cDAI.png?1696509390",
"symbol": "cDAI",
"decimals": 8,
"priceId": "cdai",
"sinceTimestamp": 1577297782
},
"buckets": [
{
"id": "tornado-cDAI-5000",
"type": "denomination",
"label": "cDAI 5000",
"address": "eth:0x22aaA7720ddd5388A3c0A3333430953C68f1849b",
"sinceTimestamp": 1577297782,
"denomination": "5000",
"anonymitySet": {
"minimumAmounts": [
"500000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "500000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "500000000000"
}
}
},
{
"id": "tornado-cDAI-50000",
"type": "denomination",
"label": "cDAI 50000",
"address": "eth:0x03893a7c7463AE47D46bc7f091665f1893656003",
"sinceTimestamp": 1616155055,
"denomination": "50000",
"anonymitySet": {
"minimumAmounts": [
"5000000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "5000000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "5000000000000"
}
}
},
{
"id": "tornado-cDAI-500000",
"type": "denomination",
"label": "cDAI 500000",
"address": "eth:0x2717c5e28cf931547B621a5dddb772Ab6A35B701",
"sinceTimestamp": 1616135923,
"denomination": "500000",
"anonymitySet": {
"minimumAmounts": [
"50000000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "50000000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "50000000000000"
}
}
},
{
"id": "tornado-cDAI-5000000",
"type": "denomination",
"label": "cDAI 5000000",
"address": "eth:0xD21be7248e0197Ee08E0c20D4a96DEBdaC3D20Af",
"sinceTimestamp": 1616115450,
"denomination": "5000000",
"anonymitySet": {
"minimumAmounts": [
"500000000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "500000000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "500000000000000"
}
}
}
]
},
{
"token": {
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"iconUrl": "https://assets.coingecko.com/coins/images/9956/large/Badge_Dai.png?1696509996",
"symbol": "DAI",
"decimals": 18,
"priceId": "dai",
"sinceTimestamp": 1576534688
},
"buckets": [
{
"id": "tornado-DAI-100",
"type": "denomination",
"label": "DAI 100",
"address": "eth:0xD4B88Df4D29F5CedD6857912842cff3b20C8Cfa3",
"sinceTimestamp": 1576534688,
"denomination": "100",
"anonymitySet": {
"minimumAmounts": [
"100000000000000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "100000000000000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "100000000000000000000"
}
}
},
{
"id": "tornado-DAI-1000",
"type": "denomination",
"label": "DAI 1000",
"address": "eth:0xFD8610d20aA15b7B2E3Be39B396a1bC3516c7144",
"sinceTimestamp": 1577297383,
"denomination": "1000",
"anonymitySet": {
"minimumAmounts": [
"1000000000000000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "1000000000000000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "1000000000000000000000"
}
}
},
{
"id": "tornado-DAI-10000",
"type": "denomination",
"label": "DAI 10000",
"address": "eth:0x07687e702b410Fa43f4cB4Af7FA097918ffD2730",
"sinceTimestamp": 1616114822,
"denomination": "10000",
"anonymitySet": {
"minimumAmounts": [
"10000000000000000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "10000000000000000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "10000000000000000000000"
}
}
},
{
"id": "tornado-DAI-100000",
"type": "denomination",
"label": "DAI 100000",
"address": "eth:0x23773E65ed146A459791799d01336DB287f25334",
"sinceTimestamp": 1616115387,
"denomination": "100000",
"anonymitySet": {
"minimumAmounts": [
"100000000000000000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "100000000000000000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "100000000000000000000000"
}
}
}
]
},
{
"token": {
"address": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
"iconUrl": "https://assets.coingecko.com/coins/images/279/large/ethereum.png?1595348880",
"symbol": "ETH",
"decimals": 18,
"priceId": "ethereum",
"sinceTimestamp": 1576523323
},
"buckets": [
{
"id": "tornado-ETH-0.1",
"type": "denomination",
"label": "ETH 0.1",
"address": "eth:0x12D66f87A04A9E220743712cE6d9bB1B5616B8Fc",
"sinceTimestamp": 1576523323,
"denomination": "0.1",
"anonymitySet": {
"minimumAmounts": [
"100000000000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "100000000000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "100000000000000000"
}
}
},
{
"id": "tornado-ETH-1",
"type": "denomination",
"label": "ETH 1",
"address": "eth:0x47CE0C6eD5B0Ce3d3A51fdb1C52DC66a7c3c2936",
"sinceTimestamp": 1576534673,
"denomination": "1",
"anonymitySet": {
"minimumAmounts": [
"1000000000000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "1000000000000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "1000000000000000000"
}
}
},
{
"id": "tornado-ETH-10",
"type": "denomination",
"label": "ETH 10",
"address": "eth:0x910Cbd523D972eb0a6f4cAe4618aD62622b39DbF",
"sinceTimestamp": 1576536415,
"denomination": "10",
"anonymitySet": {
"minimumAmounts": [
"10000000000000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "10000000000000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "10000000000000000000"
}
}
},
{
"id": "tornado-ETH-100",
"type": "denomination",
"label": "ETH 100",
"address": "eth:0xA160cdAB225685dA1d56aa342Ad8841c3b53f291",
"sinceTimestamp": 1577296976,
"denomination": "100",
"anonymitySet": {
"minimumAmounts": [
"100000000000000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "100000000000000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "100000000000000000000"
}
}
}
]
},
{
"token": {
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"iconUrl": "https://assets.coingecko.com/coins/images/6319/large/usdc.png?1696506694",
"symbol": "USDC",
"decimals": 6,
"priceId": "usd-coin",
"sinceTimestamp": 1577298068
},
"buckets": [
{
"id": "tornado-USDC-100",
"type": "denomination",
"label": "USDC 100",
"address": "eth:0xd96f2B1c14Db8458374d9Aca76E26c3D18364307",
"sinceTimestamp": 1577298068,
"denomination": "100",
"anonymitySet": {
"minimumAmounts": [
"100000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "100000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "100000000"
}
}
},
{
"id": "tornado-USDC-1000",
"type": "denomination",
"label": "USDC 1000",
"address": "eth:0x4736dCf1b7A3d580672CcE6E7c65cd5cc9cFBa9D",
"sinceTimestamp": 1577298155,
"denomination": "1000",
"anonymitySet": {
"minimumAmounts": [
"1000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "1000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "1000000000"
}
}
}
]
},
{
"token": {
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"iconUrl": "https://assets.coingecko.com/coins/images/325/large/Tether.png?1696501661",
"symbol": "USDT",
"decimals": 6,
"priceId": "tether",
"sinceTimestamp": 1577298900
},
"buckets": [
{
"id": "tornado-USDT-100",
"type": "denomination",
"label": "USDT 100",
"address": "eth:0x169AD27A470D064DEDE56a2D3ff727986b15D52B",
"sinceTimestamp": 1577298900,
"denomination": "100",
"anonymitySet": {
"minimumAmounts": [
"100000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "100000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "100000000"
}
}
},
{
"id": "tornado-USDT-1000",
"type": "denomination",
"label": "USDT 1000",
"address": "eth:0x0836222F2B2B24A3F36f98668Ed8F0B38D1a872f",
"sinceTimestamp": 1577298985,
"denomination": "1000",
"anonymitySet": {
"minimumAmounts": [
"1000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "1000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "1000000000"
}
}
}
]
},
{
"token": {
"address": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
"iconUrl": "https://assets.coingecko.com/coins/images/7598/large/wrapped_bitcoin_wbtc.png?1696507857",
"symbol": "WBTC",
"decimals": 8,
"priceId": "wrapped-bitcoin",
"sinceTimestamp": 1616123193
},
"buckets": [
{
"id": "tornado-WBTC-0.1",
"type": "denomination",
"label": "WBTC 0.1",
"address": "eth:0x178169B423a011fff22B9e3F3abeA13414dDD0F1",
"sinceTimestamp": 1616134868,
"denomination": "0.1",
"anonymitySet": {
"minimumAmounts": [
"10000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "10000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "10000000"
}
}
},
{
"id": "tornado-WBTC-1",
"type": "denomination",
"label": "WBTC 1",
"address": "eth:0x610B717796ad172B316836AC95a2ffad065CeaB4",
"sinceTimestamp": 1616123193,
"denomination": "1",
"anonymitySet": {
"minimumAmounts": [
"100000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "100000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "100000000"
}
}
},
{
"id": "tornado-WBTC-10",
"type": "denomination",
"label": "WBTC 10",
"address": "eth:0xbB93e510BbCD0B7beb5A853875f9eC60275CF498",
"sinceTimestamp": 1616135758,
"denomination": "10",
"anonymitySet": {
"minimumAmounts": [
"1000000000"
]
},
"deposit": {
"event": "0xa945e51eec50ab98c161376f0db4cf2aeba3ec92755fe2fcd388bdbbb80ff196",
"extractor": "fixedAmount",
"params": {
"amount": "1000000000"
}
},
"withdrawal": {
"event": "0xe9e508bad6d4c3227e881ca19068f099da81b5164dd6d62b2eaf1e8bc6c34931",
"extractor": "fixedAmount",
"params": {
"amount": "1000000000"
}
}
}
]
}
],
"trackedOn": [
"ethereum"
],
"upgradesAndGovernance": {
"content": "TORN holders govern through the Governance contract, after a vote and a timelock. They cannot change the pools. They control the InstanceRegistry the router reads its pool list from, the RelayerRegistry, the FeeManager, the TORN token and the IPFS hash of the app on tornadocash.eth. A malicious registry upgrade could steal tokens users approved to the router. A malicious app could steal the notes of users who load it. Removing relayers from the registry hides them from the app, while the pools still accept any relayer.",
"governanceInfo": {
"upgrades": {
"Normal upgrade path": "Lock and optionally delegate TORN in the [Governance contract](https://etherscan.io/address/0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce) → submit a proposal with at least **1.00 K TORN** → wait 1m 15s → vote for 5d (extended by 6h if the outcome changes during the last 1h) → pass with a simple majority and **100.00 K TORN** quorum → wait 2d → permissionless execution within 3d. The DAO controls protocol and periphery components, but cannot upgrade or modify existing pools.",
"Exit window": "**2d** for DAO-controlled changes — an accepted proposal remains timelocked for this period before it can be executed. Existing Tornado Cash pools are immutable and cannot be upgraded by the DAO."
},
"tokenGovernance": {
"Governance token": "`TORN`, 1 token = 1 vote, delegated. Total supply: **9.99 M TORN**, DAO-owned TORN (unavailable for voting): **4.73 M TORN**, staked for voting: **2.57 M TORN**, the rest is circulating supply.",
"Stake lock": "After voting or proposing, staked tokens are locked for **5d 6h** after proposal ends, preventing governance hopping.",
"Voting venue": "[Governance contract](https://etherscan.io/address/0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce) on Ethereum. Proposals are viewable on the governance page of the app, see the App section above.",
"Proposal threshold": "**1.00 K TORN** locked in governance.",
"Quorum": "**100.00 K TORN**, with a simple majority required for acceptance.",
"Execution model": "**Permissionless execution after an onchain vote and timelock.** An accepted proposal waits 2d and can then be executed by anyone within 3d. Proposal executable payload is committed in the `propose()` transaction."
}
}
}
}
+1 -1
+1 -1
{
"adversaries": {
"promise": {
"protects": "recipient",
"text": "Hides which registered recipient a stealth payment is for. The payer knows; sender, asset, amount and where the funds go next are public."
},
"adversaries": [
{
"id": "publicObserver",
"label": "Public observer",
"description": "Everyone with a block explorer and some basic tools. Sees every public onchain event, but does no correlation beyond following links.",
"examples": "A curious counterparty, an employer, a journalist."
},
{
"id": "chainAnalyst",
"label": "Chain analyst",
"description": "Scrapes all public data and correlates it: timing, amounts, gas and wallet fingerprints, address clusters.",
"examples": "Chain analytics firms, ZachXBT, data brokers."
},
{
"id": "networkObserver",
"label": "Network observer",
"description": "Sits between the user and the services and sees traffic only: ISPs, VPNs, Tor exits, public RPCs and relayers. Learns IP addresses, timing, fingerprints and ciphertext. Services the operator runs count as the insider.",
"examples": "Infura or Alchemy, a Tornado relayer, a wallet vendor selling telemetry, Google captcha or analytics in the dapp frontend."
},
{
"id": "privilegedInsider",
"label": "Privileged insider",
"description": "Holds an operator role, custodies funds, receives keys or plaintext by design, or delivers the client: upgrade admin, custodian, view key holder, enclave operator, association set provider, hosted prover, registry, frontend host.",
"examples": "A compliance backdoor key, a DAO with an upgrade key, a KMS committee, an ASP operator, a custodial bridge."
},
{
"id": "futureAdversary",
"label": "Future adversary",
"description": "Harvest now, decrypt later. Holds every byte ever written onchain plus any retained logs, and breaks all public-key cryptography, by quantum computer or new mathematics: elliptic curves, pairings, RSA, lattices and isogenies. Hashes, Poseidon included, and symmetric ciphers survive.",
"description": "Harvest now, decrypt later. Holds every byte ever published and runs the known quantum attacks: elliptic curves, pairings and RSA fall. Hashes, symmetric ciphers and post-quantum schemes stand until an attack on them is known.",
"examples": "An intelligence agency archiving chain data today, then anyone once a break is public."
}
],
"fields": [
{
"id": "sender",
"label": "Sender",
"subject": "Sender",
"promiseLabel": "Sender privacy",
"description": "The Ethereum address that funds entered from, or that initiated a transfer."
},
{
"id": "recipient",
"label": "Recipient",
"subject": "Recipient",
"promiseLabel": "Recipient privacy",
"description": "Who receives the funds: the address they exit to, the receiver of a transfer, or whoever controls a one-time receiving address."
},
{
"id": "amount",
"label": "Amount",
"subject": "Amounts",
"promiseLabel": "Amount privacy",
"description": "The value moved."
},
{
"id": "asset",
"label": "Asset",
"subject": "Asset",
"promiseLabel": "Asset privacy",
"description": "Which token is moved."
},
{
"id": "linkage",
"label": "Link",
"subject": "Link",
"promiseLabel": "Link privacy",
"description": "Whether the entry and exit of the same funds, or sender and recipient of the same transfer, can be tied together."
}
],
"cells": {
"publicObserver": {
"sentiment": "good",
"exposureShort": "Each payment goes to a fresh stealth address, and only the recipient's viewing key shows whose it is.",
"exposureContinued": "The registry lists every recipient who could be behind it, with their key history.",
"advice": "Withdraw to a fresh address that is not registered and has no public link to the user.",
"sources": [
{
"contract": "Umbra",
"title": "Announcement and TokenWithdrawal publish the fund path"
},
{
"contract": "StealthKeyRegistry",
"title": "StealthKeyChanged publishes recipients and key changes"
},
{
"title": "Matching decrypts the secret with the viewing key and checks the stealth address",
"url": "https://github.com/ScopeLift/umbra-protocol/blob/947c4f3b9b89f6cf5d69b2d43d3cffec673da655/umbra-js/src/classes/Umbra.ts#L707-L721"
}
],
"id": "publicObserver",
"value": "Recipient private",
"alsoExposed": []
},
"chainAnalyst": {
"sentiment": "good",
"exposureShort": "Any of the 11,983 registered recipients could be behind a stealth address.",
"exposureContinued": "Registrations are rare and public, so a payment that lands minutes after one points to that registrant. Several payments withdrawn to one address share a recipient.",
"advice": "Register long before anyone pays the user, and withdraw each payment to its own address. Exit through a relayer for tokens, so none of the user's wallets pay gas for the receiving address.",
"sources": [
{
"contract": "StealthKeyRegistry",
"title": "Each registration is public with its block"
},
{
"title": "Kovács and Seres: reuse heuristics and their reach on mainnet (sections 6 and 7)",
"url": "https://arxiv.org/html/2308.01703v2#S6"
},
{
"title": "The app warns about registered, named and sender destinations, and lets the user proceed",
"url": "https://github.com/ScopeLift/umbra-protocol/blob/947c4f3b9b89f6cf5d69b2d43d3cffec673da655/frontend/src/utils/address.ts#L146-L241"
}
],
"id": "chainAnalyst",
"value": "Recipient private",
"alsoExposed": []
},
"networkObserver": {
"sentiment": "warning",
"exposureShort": "The hosted app checks the payee's address with its Alchemy RPC seconds before each payment, so timing ties the payee to the payment.",
"exposureContinued": "When the payee withdraws, the same RPC receives their wallet address and the withdrawal address in one session. The wallet's own RPC receives the wallet address together with the matched stealth addresses. On connect, the wallet library also sends the user's wallet address to Cloudflare's RPC to look up its ENS name.",
"advice": "Pay and withdraw from a local build with all RPC URLs and the user's wallet pointed at their own node, and block cloudflare-eth.com.",
"sources": [
{
"title": "Sending checks the recipient against a sanctions list through the app's mainnet RPC",
"url": "https://github.com/ScopeLift/umbra-protocol/blob/947c4f3b9b89f6cf5d69b2d43d3cffec673da655/umbra-js/src/classes/Umbra.ts#L219-L227"
},
{
"title": "Connecting checks the wallet address through the same RPC",
"url": "https://github.com/ScopeLift/umbra-protocol/blob/947c4f3b9b89f6cf5d69b2d43d3cffec673da655/frontend/src/store/wallet.ts#L273"
},
{
"title": "Withdrawing checks the destination through the same RPC",
"url": "https://github.com/ScopeLift/umbra-protocol/blob/947c4f3b9b89f6cf5d69b2d43d3cffec673da655/frontend/src/components/AccountReceiveTable.vue#L736"
},
{
"title": "Matched stealth addresses go to the wallet RPC in one balance call",
"url": "https://github.com/ScopeLift/umbra-protocol/blob/947c4f3b9b89f6cf5d69b2d43d3cffec673da655/frontend/src/components/AccountReceiveTable.vue#L606-L625"
}
],
"id": "networkObserver",
"value": "Recipient at risk",
"alsoExposed": []
},
"privilegedInsider": {
"sentiment": "warning",
"exposureShort": "The hosted app gives the operator the user's wallet address on every scan and withdrawal address in the same session.",
"exposureContinued": "Token withdrawals also hand its relayer the stealth address. The operator serves the app and can change it at any time. The contracts are immutable, and only the user holds their viewing key.",
"advice": "Run an inspected local build of the client instead of the hosted frontend. Leave its indexer URL empty, so it reads payments from the user's node.",
"sources": [
{
"title": "Each scan first asks the indexer for the connected wallet's registration",
"url": "https://github.com/ScopeLift/umbra-protocol/blob/947c4f3b9b89f6cf5d69b2d43d3cffec673da655/umbra-js/src/utils/utils.ts#L336-L349"
},
{
"title": "The registry read stores no block, so the lookup repeats on every scan",
"url": "https://github.com/ScopeLift/umbra-protocol/blob/947c4f3b9b89f6cf5d69b2d43d3cffec673da655/frontend/src/store/wallet.ts#L605-L615"
},
{
"title": "Every withdrawal sends the destination to the operator's API",
"url": "https://github.com/ScopeLift/umbra-protocol/blob/947c4f3b9b89f6cf5d69b2d43d3cffec673da655/frontend/src/utils/address.ts#L201-L214"
},
{
"title": "Token withdrawals send the stealth address to the relayer",
"url": "https://github.com/ScopeLift/umbra-protocol/blob/947c4f3b9b89f6cf5d69b2d43d3cffec673da655/frontend/src/components/AccountReceiveTable.vue#L767-L768"
}
],
"id": "privilegedInsider",
"value": "Recipient at risk",
"alsoExposed": []
},
"futureAdversary": {
"sentiment": "bad",
"exposureShort": "Whoever breaks elliptic-curve cryptography matches every past payment to its registered recipient from chain data alone.",
"exposureContinued": "The registry holds each recipient's public keys, and each announcement the payer's one-time key and the encrypted secret. Recovering the private keys decrypts the secret and confirms the stealth address.",
"sources": [
{
"contract": "Umbra",
"title": "Announcement archives the one-time key and ciphertext"
},
{
"contract": "StealthKeyRegistry",
"title": "Historical public viewing and spending keys"
},
{
"title": "A shared secret from elliptic-curve keys encrypts the secret",
"url": "https://github.com/ScopeLift/umbra-protocol/blob/947c4f3b9b89f6cf5d69b2d43d3cffec673da655/umbra-js/src/classes/KeyPair.ts#L121-L157"
}
],
"id": "futureAdversary",
"value": "Recipient exposed",
"alsoExposed": []
}
}
},
"anonymitySet": {
"type": "key-registrations",
"registry": "eth:0x31fe56609C65Cd0C510E7125f051D440424D38f3",
"sinceTimestamp": 1629943007,
"event": "0xe879dede910dd3b22239a11044df83c95adcd4b54003516f42866cc1fe4f0a19",
"extractor": "umbraStealthKeyChanged"
},
"attributes": [
{
"id": "anyAmount",
"label": "Any amount",
"description": "Deposits and withdrawals can have any size."
},
{
"id": "stealthAddresses",
"label": "Stealth addresses",
"description": "Uses fresh, one-time recipient addresses to obscure who controls the receiving address."
}
],
"category": {
"id": "stealthAddress",
"label": "Stealth address",
"description": "Payments land on fresh one-time addresses. Hides which recipient a payment is for."
},
"exitWindow": {
"value": "Infinite",
"sentiment": "good",
"orderHint": 9007199254740991,
"description": "The contracts are immutable. The toll applies only to new payments, so recipients can always withdraw what they received.",
"walkawayTest": {
"passed": true
}
},
"reproducibility": {
"value": "Reproducible",
"sentiment": "good",
"description": "The contracts, the umbra-js library and the frontend are open source and build locally. The indexer and the relayer API behind the hosted app are closed."
},
"riskSummary": "## Funds can be lost if\n1. an unsupported ERC-20, such as a fee-on-transfer or rebasing token, causes the Umbra contract's internal accounting to diverge from its token balance.\n
\n## Privacy can be lost if\n1. the operator links the user's wallet to their stealth addresses, since the hosted app sends it both in one session (see privileged insider).\n2. Alchemy, the hosted app's RPC, receives the payee's address seconds before each payment, so timing ties the payee to it (see network observer).\n3. elliptic-curve cryptography is broken, which matches every past payment to its registered recipient (see future adversary).\n
\n## New payments can be stopped if\n1. the Umbra owner raises the toll on payments through the contract, which has no cap.",
"tokens": [
{
"token": {
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"iconUrl": "https://assets.coingecko.com/coins/images/9956/large/Badge_Dai.png?1696509996",
"symbol": "DAI",
"decimals": 18,
"priceId": "dai",
"sinceTimestamp": 1619813937
},
"buckets": [
{
"id": "umbra-DAI",
"type": "pool",
"label": "DAI",
"address": "eth:0xFb2dc580Eed955B528407b4d36FfaFe3da685401",
"sinceTimestamp": 1619813937,
"deposit": {
"event": "0x29877766fa2bfe3b90008d6d92f965eca91cbc5757ed775740e460799fb92219",
"extractor": "umbraAmount",
"params": {
"tokenAddress": "0x6B175474E89094C44Da98b954EedeAC495271d0F"
}
},
"withdrawal": {
"event": "0x30eb3583ad09933b693a45452ab07512244cdbc5868701aa004c27b7b267c249",
"extractor": "umbraAmount",
"params": {
"tokenAddress": "0x6B175474E89094C44Da98b954EedeAC495271d0F"
}
}
}
]
},
{
"token": {
"address": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
"iconUrl": "https://assets.coingecko.com/coins/images/279/large/ethereum.png?1595348880",
"symbol": "ETH",
"decimals": 18,
"priceId": "ethereum",
"sinceTimestamp": 1619813937
},
"buckets": [
{
"id": "umbra-ETH",
"type": "pool",
"label": "ETH",
"address": "eth:0xFb2dc580Eed955B528407b4d36FfaFe3da685401",
"sinceTimestamp": 1619813937,
"deposit": {
"event": "0x29877766fa2bfe3b90008d6d92f965eca91cbc5757ed775740e460799fb92219",
"extractor": "umbraAmount",
"params": {
"tokenAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
}
},
"withdrawal": {
"event": "0x29877766fa2bfe3b90008d6d92f965eca91cbc5757ed775740e460799fb92219",
"extractor": "umbraAmount",
"params": {
"tokenAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
}
}
}
]
},
{
"token": {
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"iconUrl": "https://assets.coingecko.com/coins/images/6319/large/usdc.png?1696506694",
"symbol": "USDC",
"decimals": 6,
"priceId": "usd-coin",
"sinceTimestamp": 1619813937
},
"buckets": [
{
"id": "umbra-USDC",
"type": "pool",
"label": "USDC",
"address": "eth:0xFb2dc580Eed955B528407b4d36FfaFe3da685401",
"sinceTimestamp": 1619813937,
"deposit": {
"event": "0x29877766fa2bfe3b90008d6d92f965eca91cbc5757ed775740e460799fb92219",
"extractor": "umbraAmount",
"params": {
"tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
}
},
"withdrawal": {
"event": "0x30eb3583ad09933b693a45452ab07512244cdbc5868701aa004c27b7b267c249",
"extractor": "umbraAmount",
"params": {
"tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
}
}
}
]
},
{
"token": {
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"iconUrl": "https://assets.coingecko.com/coins/images/325/large/Tether.png?1696501661",
"symbol": "USDT",
"decimals": 6,
"priceId": "tether",
"sinceTimestamp": 1619813937
},
"buckets": [
{
"id": "umbra-USDT",
"type": "pool",
"label": "USDT",
"address": "eth:0xFb2dc580Eed955B528407b4d36FfaFe3da685401",
"sinceTimestamp": 1619813937,
"deposit": {
"event": "0x29877766fa2bfe3b90008d6d92f965eca91cbc5757ed775740e460799fb92219",
"extractor": "umbraAmount",
"params": {
"tokenAddress": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
}
},
"withdrawal": {
"event": "0x30eb3583ad09933b693a45452ab07512244cdbc5868701aa004c27b7b267c249",
"extractor": "umbraAmount",
"params": {
"tokenAddress": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
}
}
}
]
},
{
"token": {
"address": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
"iconUrl": "https://assets.coingecko.com/coins/images/7598/large/wrapped_bitcoin_wbtc.png?1696507857",
"symbol": "WBTC",
"decimals": 8,
"priceId": "wrapped-bitcoin",
"sinceTimestamp": 1619813937
},
"buckets": [
{
"id": "umbra-WBTC",
"type": "pool",
"label": "WBTC",
"address": "eth:0xFb2dc580Eed955B528407b4d36FfaFe3da685401",
"sinceTimestamp": 1619813937,
"deposit": {
"event": "0x29877766fa2bfe3b90008d6d92f965eca91cbc5757ed775740e460799fb92219",
"extractor": "umbraAmount",
"params": {
"tokenAddress": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
}
},
"withdrawal": {
"event": "0x30eb3583ad09933b693a45452ab07512244cdbc5868701aa004c27b7b267c249",
"extractor": "umbraAmount",
"params": {
"tokenAddress": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
}
}
}
]
}
],
"trackedOn": [
"ethereum"
],
"upgradesAndGovernance": {
"content": "The Umbra and StealthKeyRegistry contracts are immutable. The Umbra owner sets the ETH toll on every payment through the contract and the addresses that collect it, instantly and without a cap. A high toll stops new payments. ScopeLift changes the hosted app, its indexer and its relayer at will."
}
}
+13 -9
+13 -9
{
"adversaries": {
"promise": {
"protects": "amount",
"text": "Hides balances and transfer amounts. Senders, recipients and every wrap and unwrap amount are public."
},
"adversaries": [
{
"id": "publicObserver",
"label": "Public observer",
"description": "Everyone with a block explorer and some basic tools. Sees every public onchain event, but does no correlation beyond following links.",
"examples": "A curious counterparty, an employer, a journalist."
},
{
"id": "chainAnalyst",
"label": "Chain analyst",
"description": "Scrapes all public data and correlates it: timing, amounts, gas and wallet fingerprints, address clusters.",
"examples": "Chain analytics firms, ZachXBT, data brokers."
},
{
"id": "networkObserver",
"label": "Network observer",
"description": "Sits between the user and the services and sees traffic only: ISPs, VPNs, Tor exits, public RPCs and relayers. Learns IP addresses, timing, fingerprints and ciphertext. Services the operator runs count as the insider.",
"examples": "Infura or Alchemy, a Tornado relayer, a wallet vendor selling telemetry, Google captcha or analytics in the dapp frontend."
},
{
"id": "privilegedInsider",
"label": "Privileged insider",
"description": "Holds an operator role, custodies funds, receives keys or plaintext by design, or delivers the client: upgrade admin, custodian, view key holder, enclave operator, association set provider, hosted prover, registry, frontend host.",
"examples": "A compliance backdoor key, a DAO with an upgrade key, a KMS committee, an ASP operator, a custodial bridge."
},
{
"id": "futureAdversary",
"label": "Future adversary",
"description": "Harvest now, decrypt later. Holds every byte ever written onchain plus any retained logs, and breaks all public-key cryptography, by quantum computer or new mathematics: elliptic curves, pairings, RSA, lattices and isogenies. Hashes, Poseidon included, and symmetric ciphers survive.",
"description": "Harvest now, decrypt later. Holds every byte ever published and runs the known quantum attacks: elliptic curves, pairings and RSA fall. Hashes, symmetric ciphers and post-quantum schemes stand until an attack on them is known.",
"examples": "An intelligence agency archiving chain data today, then anyone once a break is public."
}
],
"fields": [
{
"id": "sender",
"label": "Sender",
"subject": "Sender",
"promiseLabel": "Sender privacy",
"description": "The Ethereum address that funds entered from, or that initiated a transfer."
},
{
"id": "recipient",
"label": "Recipient",
"subject": "Recipient",
"promiseLabel": "Recipient privacy",
"description": "Who receives the funds: the address they exit to, the receiver of a transfer, or whoever controls a one-time receiving address."
},
{
"id": "amount",
"label": "Amount",
"subject": "Amounts",
"promiseLabel": "Amount privacy",
"description": "The value moved."
},
{
"id": "asset",
"label": "Asset",
"subject": "Asset",
"promiseLabel": "Asset privacy",
"description": "Which token is moved."
},
{
"id": "linkage",
"label": "Link",
"subject": "Link",
"promiseLabel": "Link privacy",
"description": "Whether the entry and exit of the same funds, or sender and recipient of the same transfer, can be tied together."
}
],
"cells": {
"publicObserver": {
"sentiment": "warning",
"exposureShort": "Wraps and unwraps publish their amounts, while confidential transfers keep theirs encrypted.",
"exposureContinued": "Either party to a transfer can disclose its amount onchain at any time.",
"advice": "Pay and get paid inside the confidential token, and unwrap only what the user needs.",
"interior": {
"sender": "exposed",
"recipient": "exposed",
"amount": "private",
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "Wrap event carries the clear amount",
"url": "https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/blob/23ba15402346027f2416667acbb1e741179f8485/contracts/token/ERC7984/extensions/ERC7984ERC20Wrapper.sol#L256"
},
{
"title": "Unwrap makes the burned amount publicly decryptable",
"url": "https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/blob/23ba15402346027f2416667acbb1e741179f8485/contracts/token/ERC7984/extensions/ERC7984ERC20Wrapper.sol#L262-L268"
},
{
"title": "Either party can disclose a transfer amount",
"url": "https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/blob/23ba15402346027f2416667acbb1e741179f8485/contracts/token/ERC7984/ERC7984.sol#L202-L209"
}
],
"id": "publicObserver",
"value": "Amounts at risk",
"alsoExposed": []
},
"chainAnalyst": {
"sentiment": "warning",
"exposureShort": "An account's balance is bounded by its public wraps and unwraps, and exact if it never took part in a confidential transfer.",
"exposureContinued": "Transfer partners and timing are public, so a wrap, a transfer and an unwrap in a row pair up by amount. In October 2026, 95% of unwraps could be linked to a single wrap.",
"advice": "Transfer often, even zero amounts, and unwrap only after a while. Withdraw common amounts rather than everything at once.",
"interior": {
"sender": "exposed",
"recipient": "exposed",
"amount": {
"verdict": "atRisk",
"note": "Hidden only within an account's confidential transfers."
},
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "ERC-7984: public sender, recipient and encrypted amount per transfer",
"url": "https://eips.ethereum.org/EIPS/eip-7984"
},
{
"title": "Explorer linking unwraps to their wraps, searchable by address, handle and transaction",
"url": "https://sekuba.github.io/zama-graph/"
}
],
"id": "chainAnalyst",
"value": "Amounts at risk",
"alsoExposed": []
},
"networkObserver": {
"sentiment": "warning",
"exposureShort": "Zama's app is closed source, so what it sends to third parties is up to Zama and can change at any time.",
"exposureContinued": "Through Zama's open SDK, amounts leave the user's device only as FHE ciphertext and return encrypted to a key held only by that device. Today the app sends the user's address, chain reads and decryption requests to Zama's own servers, which forward chain reads to an RPC provider Zama does not name. Analytics wait for the user's consent.",
"advice": "Use a client built on Zama's open SDK.",
"interior": {
"sender": "exposed",
"recipient": "exposed",
"amount": "private",
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "Inputs are encrypted on the device",
"url": "https://github.com/zama-ai/relayer-sdk/blob/d06f1e585a78181135cb602109e5fa3da523b48d/src/relayer/sendEncryption.ts#L133-L146"
},
{
"title": "Balance reads use a device ML-KEM key pair",
"url": "https://github.com/zama-ai/relayer-sdk/blob/d06f1e585a78181135cb602109e5fa3da523b48d/src/relayer/userDecrypt.ts#L85-L89"
},
{
"title": "The app's content security policy lists every endpoint it contacts",
"url": "https://app.zama.org"
},
{
"title": "The SDK the app bundles (@zama-fhe/sdk 3.6.0) is open source",
"url": "https://github.com/zama-ai/sdk"
}
],
"id": "networkObserver",
"value": "Amounts at risk",
"alsoExposed": []
},
"privilegedInsider": {
"sentiment": "bad",
"exposureShort": "Any 5 of the 13 KMS operators can combine their key shares and decrypt every balance and transfer ever made.",
"exposureContinued": "The token owner can instantly appoint an observer that sees all amounts forever, or upgrade the token and the ACL. Zama serves its closed-source app, so it can read amounts before they are encrypted.",
"interior": {
"sender": "exposed",
"recipient": "exposed",
"amount": "exposed",
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "KMS parties and key-share threshold",
"url": "https://github.com/zama-ai/kms/blob/b5cd5cf465dc488ff04ac8c19f3ef12877abffa0/ai-docs/ARCHITECTURE.md#L22-L25"
},
{
"title": "Observer gets a wildcard delegation without expiration",
"url": "https://github.com/zama-ai/protocol-apps/blob/85eef95c797da20875fe7eeae7f8d212d760486f/contracts/confidential-wrapper/contracts/ConfidentialWrapper.sol#L395-L403"
},
{
"title": "Zama's official app",
"url": "https://docs.zama.org/protocol/protocol-apps/apps"
}
],
"id": "privilegedInsider",
"value": "Amounts exposed",
"alsoExposed": []
},
"futureAdversary": {
"sentiment": "bad",
"exposureShort": "One long-lived lattice key protects every balance and transfer amount, and anyone can download the ciphertexts today.",
"exposureContinued": "Balance reads also publish decryption shares on the Zama Gateway chain, encrypted to each user with ML-KEM, also lattice-based. Whoever breaks lattice cryptography, or later obtains enough KMS key shares, decrypts the entire history.",
"exposureShort": "Whoever breaks elliptic-curve cryptography recovers a user's wallet key from any past transaction and can have the KMS decrypt that user's history.",
"exposureContinued": "A wallet signature alone authorizes decryption, permissions on past balances and transfers never expire, and the KMS encrypts its replies to whatever key the request names. The ciphertexts themselves rest on lattice assumptions with no known quantum attack, and anyone can download them today.",
"interior": {
"sender": "exposed",
"recipient": "exposed",
"amount": "exposed",
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "Coprocessor ciphertext store (public listing)",
"url": "https://coprocessor-1.mainnet.zama.org/"
"contract": "Decryption",
"title": "A wallet signature authorizes a user decryption request"
},
{
"title": "Gateway publishes encrypted decryption shares",
"url": "https://github.com/zama-ai/fhevm/blob/94f1f3b35c71175dc68bb36887e0525f7c5d80c5/gateway-contracts/contracts/Decryption.sol#L808-L817"
"contract": "ACL",
"title": "Permissions on past ciphertexts have no expiry"
},
{
"title": "ML-KEM-512 encryption of decryption shares",
"title": "Replies are encrypted to the key the request names",
"url": "https://github.com/zama-ai/kms/blob/b5cd5cf465dc488ff04ac8c19f3ef12877abffa0/core/service/src/cryptography/hybrid_ml_kem.rs"
},
{
"title": "Coprocessor ciphertext store (public listing)",
"url": "https://coprocessor-1.mainnet.zama.org/"
}
],
"id": "futureAdversary",
"value": "Amounts exposed",
"alsoExposed": []
}
}
},
"anonymitySet": {
"type": "not-applicable",
"description": "Only amounts are hidden. Every transfer names its sender and recipient."
},
"attributes": [
{
"id": "fhe",
"label": "FHE",
"description": "Uses fully homomorphic encryption for private computation over encrypted values."
},
{
"id": "privateAmounts",
"label": "Private amounts",
"description": "Transfer amounts are private, while sender and recipient addresses remain public."
},
{
"id": "anyAmount",
"label": "Any amount",
"description": "Deposits and withdrawals can have any size."
},
{
"id": "defi",
"label": "DeFi",
"description": "Interop with DeFi vaults from within the confidential token."
}
],
"category": {
"id": "confidentialAmounts",
"label": "Confidential amounts",
"description": "Accounts and counterparties are public, balances and transfer amounts are encrypted."
},
"exitWindow": {
"value": "None",
"sentiment": "bad",
"orderHint": 0,
"description": "The governance multisigs upgrade the contracts instantly, before users can leave.",
"walkawayTest": {
"passed": false,
"reason": "Every unwrap needs a decryption signed by 7 of 13 KMS operators, and every input needs Zama's coprocessor."
}
},
"quantumResistant": true,
"reproducibility": {
"value": "Partially reproducible",
"sentiment": "warning",
"description": "The contracts, the SDK and the KMS and coprocessor sources are public. Zama's app source is unpublished."
},
"riskSummary": "## Funds can be stolen if\n1. either governance multisig passes a malicious upgrade of the confidential tokens or Zama's protocol contracts, which takes effect instantly.\n2. the current or any retained KMS signer set, which either multisig can create or retune instantly, attests an inflated unwrap amount.\n3. Zama's coprocessor (1/1) accepts invalid encrypted inputs that bypass balance checks.\n
\n## Funds can be lost if\n1. an underlying token issuer blacklists a confidential token's address.\n2. the token owner or an underlying denylist blocks a user before they unwrap.\n3. an appointed pauser halts a token and the owner keeps it paused.\n4. the KMS or Zama's coprocessor stops or loses ciphertext data, which halts every unwrap.\n
\n## Privacy can be lost if\n1. 5 of 13 KMS operators combine their key shares (see privileged insider).\n2. the token owner appoints an observer or upgrades the token (see privileged insider).\n3. Zama changes its closed-source app to leak amounts to itself or to third parties (see privileged insider and network observer).\n4. public wraps and unwraps bound a user's balance (see chain analyst).\n5. lattice cryptography is broken or old KMS key shares leak, which decrypts every published ciphertext (see future adversary).",
"riskSummary": "## Funds can be stolen if\n1. either governance multisig passes a malicious upgrade of the confidential tokens or Zama's protocol contracts, which takes effect instantly.\n2. the current or any retained KMS signer set, which either multisig can create or retune instantly, attests an inflated unwrap amount.\n3. Zama's coprocessor (1/1) accepts invalid encrypted inputs that bypass balance checks.\n
\n## Funds can be lost if\n1. an underlying token issuer blacklists a confidential token's address.\n2. the token owner or an underlying denylist blocks a user before they unwrap.\n3. an appointed pauser halts a token and the owner keeps it paused.\n4. the KMS or Zama's coprocessor stops or loses ciphertext data, which halts every unwrap.\n
\n## Privacy can be lost if\n1. 5 of 13 KMS operators combine their key shares (see privileged insider).\n2. the token owner appoints an observer or upgrades the token (see privileged insider).\n3. Zama changes its closed-source app to leak amounts to itself or to third parties (see privileged insider and network observer).\n4. public wraps and unwraps bound a user's balance (see chain analyst).\n5. elliptic-curve cryptography is broken, so anyone can impersonate a user to the KMS and decrypt that user's history (see future adversary).",
"tokens": [
{
"token": {
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"iconUrl": "https://assets.coingecko.com/coins/images/6319/large/usdc.png?1696506694",
"symbol": "USDC",
"decimals": 6,
"priceId": "usd-coin",
"sinceTimestamp": 1766750819
},
"buckets": [
{
"id": "zama-cw-cUSDC",
"type": "pool",
"label": "cUSDC token",
"address": "eth:0xe978F22157048E5DB8E5d07971376e86671672B2",
"sinceTimestamp": 1766750819,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0xe978F22157048E5DB8E5d07971376e86671672B2"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0xe978F22157048E5DB8E5d07971376e86671672B2"
}
}
}
]
},
{
"token": {
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"iconUrl": "https://assets.coingecko.com/coins/images/325/large/Tether.png?1696501661",
"symbol": "USDT",
"decimals": 6,
"priceId": "tether",
"sinceTimestamp": 1766750831
},
"buckets": [
{
"id": "zama-cw-cUSDT",
"type": "pool",
"label": "cUSDT token",
"address": "eth:0xAe0207C757Aa2B4019Ad96edD0092ddc63EF0c50",
"sinceTimestamp": 1766750831,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0xAe0207C757Aa2B4019Ad96edD0092ddc63EF0c50"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0xAe0207C757Aa2B4019Ad96edD0092ddc63EF0c50"
}
}
}
]
},
{
"token": {
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"iconUrl": "https://assets.coingecko.com/coins/images/2518/large/weth.png?1696503332",
"symbol": "WETH",
"decimals": 18,
"priceId": "weth",
"sinceTimestamp": 1766750843
},
"buckets": [
{
"id": "zama-cw-cWETH",
"type": "pool",
"label": "cWETH token",
"address": "eth:0xda9396b82634Ea99243cE51258B6A5Ae512D4893",
"sinceTimestamp": 1766750843,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0xda9396b82634Ea99243cE51258B6A5Ae512D4893"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0xda9396b82634Ea99243cE51258B6A5Ae512D4893"
}
}
}
]
},
{
"token": {
"address": "0xA12CC123ba206d4031D1c7f6223D1C2Ec249f4f3",
"iconUrl": "https://coin-images.coingecko.com/coins/images/70921/large/zama.png?1764591992",
"symbol": "ZAMA",
"decimals": 18,
"priceId": "zama",
"sinceTimestamp": 1766750867
},
"buckets": [
{
"id": "zama-cw-cZAMA",
"type": "pool",
"label": "cZAMA token",
"address": "eth:0x80CB147Fd86dC6dEe3Eee7e4Cee33d1397d98071",
"sinceTimestamp": 1766750867,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x80CB147Fd86dC6dEe3Eee7e4Cee33d1397d98071"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x80CB147Fd86dC6dEe3Eee7e4Cee33d1397d98071"
}
}
}
]
},
{
"token": {
"address": "0x27f6c8289550fCE67f6B50BeD1F519966aFE5287",
"iconUrl": "https://coin-images.coingecko.com/coins/images/70647/large/tgbp-square.png?1762953800",
"symbol": "tGBP",
"decimals": 18,
"priceId": "tokenised-gbp",
"sinceTimestamp": 1767000887
},
"buckets": [
{
"id": "zama-cw-ctGBP",
"type": "pool",
"label": "ctGBP token",
"address": "eth:0xa873750ccBafD5ec7Dd13bfD5237d7129832eDD9",
"sinceTimestamp": 1767000887,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0xa873750ccBafD5ec7Dd13bfD5237d7129832eDD9"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0xa873750ccBafD5ec7Dd13bfD5237d7129832eDD9"
}
}
}
]
},
{
"token": {
"address": "0x68749665FF8D2d112Fa859AA293F07A622782F38",
"iconUrl": "https://assets.coingecko.com/coins/images/10481/large/Tether_Gold.png?1696510471",
"symbol": "XAUt",
"decimals": 6,
"priceId": "tether-gold",
"sinceTimestamp": 1772116091
},
"buckets": [
{
"id": "zama-cw-cXAUt",
"type": "pool",
"label": "cXAUt token",
"address": "eth:0x73cc9aF9d6BEFdb3c3fAf8a5E8c05Cb95FdaEEf1",
"sinceTimestamp": 1772116091,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x73cc9aF9d6BEFdb3c3fAf8a5E8c05Cb95FdaEEf1"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x73cc9aF9d6BEFdb3c3fAf8a5E8c05Cb95FdaEEf1"
}
}
}
]
},
{
"token": {
"address": "0xbeeffABcd0dB09589Dd21854aa760C52aB4bf04F",
"iconUrl": "https://coin-images.coingecko.com/coins/images/70647/large/tgbp-square.png?1762953800",
"symbol": "bbqTGBP",
"decimals": 18,
"priceId": "tokenised-gbp",
"sinceTimestamp": 1780585031
},
"buckets": [
{
"id": "zama-cw-cbbqTGBP",
"type": "pool",
"label": "cbbqTGBP token",
"address": "eth:0xBA4cFF6ED6F7Cb2A58776dECa4E984b498446762",
"sinceTimestamp": 1780585031,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0xBA4cFF6ED6F7Cb2A58776dECa4E984b498446762"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0xBA4cFF6ED6F7Cb2A58776dECa4E984b498446762"
}
}
}
]
},
{
"token": {
"address": "0xbEEF00A59B577423653A1526c7009bdE103F542B",
"iconUrl": "https://coin-images.coingecko.com/coins/images/6319/large/USDC.png?1769615602",
"symbol": "steakcUSDC",
"decimals": 18,
"priceId": "usd-coin",
"sinceTimestamp": 1781877707
},
"buckets": [
{
"id": "zama-cw-csteakcUSDC",
"type": "pool",
"label": "csteakcUSDC token",
"address": "eth:0x66Bf74E96900D1a19c7070D939D124f2F565C458",
"sinceTimestamp": 1781877707,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x66Bf74E96900D1a19c7070D939D124f2F565C458"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x66Bf74E96900D1a19c7070D939D124f2F565C458"
}
}
}
]
},
{
"token": {
"address": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
"iconUrl": "https://assets.coingecko.com/coins/images/7598/large/wrapped_bitcoin_wbtc.png?1696507857",
"symbol": "WBTC",
"decimals": 8,
"priceId": "wrapped-bitcoin",
"sinceTimestamp": 1789148087
},
"buckets": [
{
"id": "zama-cw-cWBTC",
"type": "pool",
"label": "cWBTC token",
"address": "eth:0xd86aE89C089B380f064Fe01899B4071F1eb6Bb3d",
"sinceTimestamp": 1789148087,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0xd86aE89C089B380f064Fe01899B4071F1eb6Bb3d"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0xd86aE89C089B380f064Fe01899B4071F1eb6Bb3d"
}
}
}
]
},
{
"token": {
"address": "0x00000000eFE302BEAA2b3e6e1b18d08D69a9012a",
"iconUrl": "https://coin-images.coingecko.com/coins/images/39284/large/AUSD_1024px.png?1764684132",
"symbol": "AUSD",
"decimals": 6,
"priceId": "agora-dollar",
"sinceTimestamp": 1789146719
},
"buckets": [
{
"id": "zama-cw-cAUSD",
"type": "pool",
"label": "cAUSD token",
"address": "eth:0xEa9A15A29DD180c40442142CaeEfC491d37bfDB2",
"sinceTimestamp": 1789146719,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0xEa9A15A29DD180c40442142CaeEfC491d37bfDB2"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0xEa9A15A29DD180c40442142CaeEfC491d37bfDB2"
}
}
}
]
},
{
"token": {
"address": "0x808507121B80c02388fAd14726482e061B8da827",
"iconUrl": "https://assets.coingecko.com/coins/images/15069/large/Pendle_Logo_Normal-03.png?1696514728",
"symbol": "PENDLE",
"decimals": 18,
"priceId": "pendle",
"sinceTimestamp": 1789150991
},
"buckets": [
{
"id": "zama-cw-cPENDLE",
"type": "pool",
"label": "cPENDLE token",
"address": "eth:0x8900123F7e17709C1D80eda1E611A9503Cf1B3df",
"sinceTimestamp": 1789150991,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x8900123F7e17709C1D80eda1E611A9503Cf1B3df"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x8900123F7e17709C1D80eda1E611A9503Cf1B3df"
}
}
}
]
},
{
"token": {
"address": "0xbeef003C68896c7D2c3c60d363e8d71a49Ab2bf9",
"iconUrl": "https://coin-images.coingecko.com/coins/images/325/large/Tether.png?1696501661",
"symbol": "steakUSDT",
"decimals": 18,
"priceId": "tether",
"sinceTimestamp": 1789152239
},
"buckets": [
{
"id": "zama-cw-csteakUSDT",
"type": "pool",
"label": "csteakUSDT token",
"address": "eth:0x1F6A937119c0c34Db0a2c4F000386a3BfD4A9e73",
"sinceTimestamp": 1789152239,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x1F6A937119c0c34Db0a2c4F000386a3BfD4A9e73"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x1F6A937119c0c34Db0a2c4F000386a3BfD4A9e73"
}
}
}
]
},
{
"token": {
"address": "0xbeeff07d991C04CD640DE9F15C08ba59c4FEDEb7",
"iconUrl": "https://coin-images.coingecko.com/coins/images/325/large/Tether.png?1696501661",
"symbol": "bbqUSDT",
"decimals": 18,
"priceId": "tether",
"sinceTimestamp": 1789152695
},
"buckets": [
{
"id": "zama-cw-cbbqUSDT",
"type": "pool",
"label": "cbbqUSDT token",
"address": "eth:0x80Ae7dbCe3c1696d3eeD04Ec8348c3C432322273",
"sinceTimestamp": 1789152695,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x80Ae7dbCe3c1696d3eeD04Ec8348c3C432322273"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x80Ae7dbCe3c1696d3eeD04Ec8348c3C432322273"
}
}
}
]
},
{
"token": {
"address": "0xbeeff2C5bF38f90e3482a8b19F12E5a6D2FCa757",
"iconUrl": "https://coin-images.coingecko.com/coins/images/6319/large/USDC.png?1769615602",
"symbol": "bbqUSDC",
"decimals": 18,
"priceId": "usd-coin",
"sinceTimestamp": 1789153067
},
"buckets": [
{
"id": "zama-cw-cbbqUSDC",
"type": "pool",
"label": "cbbqUSDC token",
"address": "eth:0x501b014f86a73A7199E00cB31C0e9565Ac51e51B",
"sinceTimestamp": 1789153067,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x501b014f86a73A7199E00cB31C0e9565Ac51e51B"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x501b014f86a73A7199E00cB31C0e9565Ac51e51B"
}
}
}
]
},
{
"token": {
"address": "0x3d5EcCb62974178236A768A7ef14D3ce468Fbe91",
"iconUrl": "https://coin-images.coingecko.com/coins/images/7598/large/WBTCLOGO.png?1764496367",
"symbol": "armcWBTC",
"decimals": 18,
"priceId": "wrapped-bitcoin",
"sinceTimestamp": 1789148987
},
"buckets": [
{
"id": "zama-cw-carmcWBTC",
"type": "pool",
"label": "carmcWBTC token",
"address": "eth:0xF921A5B0634f4236B21A4e948317abf9a2E86B6f",
"sinceTimestamp": 1789148987,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0xF921A5B0634f4236B21A4e948317abf9a2E86B6f"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0xF921A5B0634f4236B21A4e948317abf9a2E86B6f"
}
}
}
]
},
{
"token": {
"address": "0x500aE64100D7DbDb640531085C2F5d40cDC8930D",
"iconUrl": "https://coin-images.coingecko.com/coins/images/325/large/Tether.png?1696501661",
"symbol": "armUSDTs",
"decimals": 18,
"priceId": "tether",
"sinceTimestamp": 1789150187
},
"buckets": [
{
"id": "zama-cw-carmUSDTs",
"type": "pool",
"label": "carmUSDTs token",
"address": "eth:0xbaC6DeDf2C10D6D381F9DBd9EFd69D93FfCef50B",
"sinceTimestamp": 1789150187,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0xbaC6DeDf2C10D6D381F9DBd9EFd69D93FfCef50B"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0xbaC6DeDf2C10D6D381F9DBd9EFd69D93FfCef50B"
}
}
}
]
},
{
"token": {
"address": "0xA2EAaD0D586cF9FD73bb2c09cF6A7E3e187D68cd",
"iconUrl": "https://coin-images.coingecko.com/coins/images/6319/large/USDC.png?1769615602",
"symbol": "armUSDCs",
"decimals": 18,
"priceId": "usd-coin",
"sinceTimestamp": 1789151411
},
"buckets": [
{
"id": "zama-cw-carmUSDCs",
"type": "pool",
"label": "carmUSDCs token",
"address": "eth:0x77F8207ee451441336538bA07a2F425780dED8DB",
"sinceTimestamp": 1789151411,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x77F8207ee451441336538bA07a2F425780dED8DB"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x77F8207ee451441336538bA07a2F425780dED8DB"
}
}
}
]
},
{
"token": {
"address": "0xBf29043164660C60A2a72Cd15FFe2304e87B6838",
"iconUrl": "https://coin-images.coingecko.com/coins/images/325/large/Tether.png?1696501661",
"symbol": "armUSDTp",
"decimals": 18,
"priceId": "tether",
"sinceTimestamp": 1789153331
},
"buckets": [
{
"id": "zama-cw-carmUSDTp",
"type": "pool",
"label": "carmUSDTp token",
"address": "eth:0x63a60aCC304b84eF829b263f28e7b636Bf77d45A",
"sinceTimestamp": 1789153331,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x63a60aCC304b84eF829b263f28e7b636Bf77d45A"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x63a60aCC304b84eF829b263f28e7b636Bf77d45A"
}
}
}
]
},
{
"token": {
"address": "0x5dc53a23AdC9f2Bed98de6F59F7F309a7c71FF2B",
"iconUrl": "https://coin-images.coingecko.com/coins/images/6319/large/USDC.png?1769615602",
"symbol": "armUSDCp",
"decimals": 18,
"priceId": "usd-coin",
"sinceTimestamp": 1789150751
},
"buckets": [
{
"id": "zama-cw-carmUSDCp",
"type": "pool",
"label": "carmUSDCp token",
"address": "eth:0x2ebBd099f66b0ca94DD82B4c06fe3eEf6AFf853c",
"sinceTimestamp": 1789150751,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x2ebBd099f66b0ca94DD82B4c06fe3eEf6AFf853c"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x2ebBd099f66b0ca94DD82B4c06fe3eEf6AFf853c"
}
}
}
]
},
{
"token": {
"address": "0x55C1B6e461a6334B567bAF0FEb5D728715446f05",
"iconUrl": "https://coin-images.coingecko.com/coins/images/6319/large/USDC.png?1769615602",
"symbol": "pendleUSDC",
"decimals": 18,
"priceId": "usd-coin",
"sinceTimestamp": 1789150499
},
"buckets": [
{
"id": "zama-cw-cpendleUSDC",
"type": "pool",
"label": "cpendleUSDC token",
"address": "eth:0xb6e5299fc56053DD5440104Fd6Fd2A3CD064edbC",
"sinceTimestamp": 1789150499,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0xb6e5299fc56053DD5440104Fd6Fd2A3CD064edbC"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0xb6e5299fc56053DD5440104Fd6Fd2A3CD064edbC"
}
}
}
]
},
{
"token": {
"address": "0x32401B9fb79065Bc15949DE0BD43927492f02F0C",
"iconUrl": "https://coin-images.coingecko.com/coins/images/39284/large/AUSD_1024px.png?1764684132",
"symbol": "fAUSDe",
"decimals": 18,
"priceId": "agora-dollar",
"sinceTimestamp": 1789148387
},
"buckets": [
{
"id": "zama-cw-cfAUSDe",
"type": "pool",
"label": "cfAUSDe token",
"address": "eth:0x76A3f985315aAc9789Cb5BF8A5bb83BFF55FD5a6",
"sinceTimestamp": 1789148387,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x76A3f985315aAc9789Cb5BF8A5bb83BFF55FD5a6"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x76A3f985315aAc9789Cb5BF8A5bb83BFF55FD5a6"
}
}
}
]
},
{
"token": {
"address": "0xb48C056C5608bA2Ee4cD94AF2bF4b1F25295Bd7e",
"iconUrl": "https://coin-images.coingecko.com/coins/images/325/large/Tether.png?1696501661",
"symbol": "fcUSDT",
"decimals": 18,
"priceId": "tether",
"sinceTimestamp": 1789388567
},
"buckets": [
{
"id": "zama-cw-cfcUSDT",
"type": "pool",
"label": "cfcUSDT token",
"address": "eth:0xA28A369Df348ac232E4DAF7B0Ef90280d8707D7F",
"sinceTimestamp": 1789388567,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0xA28A369Df348ac232E4DAF7B0Ef90280d8707D7F"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0xA28A369Df348ac232E4DAF7B0Ef90280d8707D7F"
}
}
}
]
},
{
"token": {
"address": "0xc207d3f66537D7F66456808379A0E560cF20Da36",
"iconUrl": "https://coin-images.coingecko.com/coins/images/6319/large/USDC.png?1769615602",
"symbol": "roxcUSDC",
"decimals": 18,
"priceId": "usd-coin",
"sinceTimestamp": 1789153955
},
"buckets": [
{
"id": "zama-cw-croxcUSDC",
"type": "pool",
"label": "croxcUSDC token",
"address": "eth:0xB1B18Ad1F16D744c470cb6B09Cb826AfFcc9EB30",
"sinceTimestamp": 1789153955,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0xB1B18Ad1F16D744c470cb6B09Cb826AfFcc9EB30"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0xB1B18Ad1F16D744c470cb6B09Cb826AfFcc9EB30"
}
}
}
]
},
{
"token": {
"address": "0xE0181090c22579B6A217f1522cbf8c9f1F0C1965",
"iconUrl": "https://coin-images.coingecko.com/coins/images/6319/large/USDC.png?1769615602",
"symbol": "roxUSDCy",
"decimals": 18,
"priceId": "usd-coin",
"sinceTimestamp": 1789154375
},
"buckets": [
{
"id": "zama-cw-croxUSDCy",
"type": "pool",
"label": "croxUSDCy token",
"address": "eth:0x4FCCF8046FB7FB7AB76321BD39C27453e396B88f",
"sinceTimestamp": 1789154375,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x4FCCF8046FB7FB7AB76321BD39C27453e396B88f"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x4FCCF8046FB7FB7AB76321BD39C27453e396B88f"
}
}
}
]
},
{
"token": {
"address": "0xB344e331A3cDa61D329fb3Cca2Be5942da87c418",
"iconUrl": "https://coin-images.coingecko.com/coins/images/39284/large/AUSD_1024px.png?1764684132",
"symbol": "PAPY",
"decimals": 18,
"priceId": "agora-dollar",
"sinceTimestamp": 1789151975
},
"buckets": [
{
"id": "zama-cw-cPAPY",
"type": "pool",
"label": "cPAPY token",
"address": "eth:0x9ABb8f3dC2863B1F108DeD7ea41902fEF6732A8c",
"sinceTimestamp": 1789151975,
"deposit": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"to": "0x9ABb8f3dC2863B1F108DeD7ea41902fEF6732A8c"
}
},
"withdrawal": {
"event": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"extractor": "erc20Transfer",
"params": {
"from": "0x9ABb8f3dC2863B1F108DeD7ea41902fEF6732A8c"
}
}
}
]
}
],
"trackedOn": [
"ethereum"
],
"upgradesAndGovernance": {
"content": "ZamaGovMultisigA (9/17) and ZamaGovMultisigB (3/6) each control, alone and instantly, the Aragon contract that owns the confidential tokens and Zama's protocol contracts on Ethereum. Either multisig can upgrade these contracts, change every compliance setting, manage KMS signer sets and trigger FHE key generation.\n\nSafeL2 (3/5) owns the Gateway contracts and can change coprocessors and KMS settings there or disconnect Ethereum. Any of 17 pausers can pause the ACL, and any of 17 the Gateway. Either halts every token until its owner unpauses."
}
}
+1 -1
+1 -1
{
"adversaries": {
"promise": {
"protects": "linkage",
"text": "Hides which funds leaving Ethereum come back as which, by passing through Zcash's shielded pool. Everything on Ethereum and NEAR is public."
},
"adversaries": [
{
"id": "publicObserver",
"label": "Public observer",
"description": "Everyone with a block explorer and some basic tools. Sees every public onchain event, but does no correlation beyond following links.",
"examples": "A curious counterparty, an employer, a journalist."
},
{
"id": "chainAnalyst",
"label": "Chain analyst",
"description": "Scrapes all public data and correlates it: timing, amounts, gas and wallet fingerprints, address clusters.",
"examples": "Chain analytics firms, ZachXBT, data brokers."
},
{
"id": "networkObserver",
"label": "Network observer",
"description": "Sits between the user and the services and sees traffic only: ISPs, VPNs, Tor exits, public RPCs and relayers. Learns IP addresses, timing, fingerprints and ciphertext. Services the operator runs count as the insider.",
"examples": "Infura or Alchemy, a Tornado relayer, a wallet vendor selling telemetry, Google captcha or analytics in the dapp frontend."
},
{
"id": "privilegedInsider",
"label": "Privileged insider",
"description": "Holds an operator role, custodies funds, receives keys or plaintext by design, or delivers the client: upgrade admin, custodian, view key holder, enclave operator, association set provider, hosted prover, registry, frontend host.",
"examples": "A compliance backdoor key, a DAO with an upgrade key, a KMS committee, an ASP operator, a custodial bridge."
},
{
"id": "futureAdversary",
"label": "Future adversary",
"description": "Harvest now, decrypt later. Holds every byte ever written onchain plus any retained logs, and breaks all public-key cryptography, by quantum computer or new mathematics: elliptic curves, pairings, RSA, lattices and isogenies. Hashes, Poseidon included, and symmetric ciphers survive.",
"description": "Harvest now, decrypt later. Holds every byte ever published and runs the known quantum attacks: elliptic curves, pairings and RSA fall. Hashes, symmetric ciphers and post-quantum schemes stand until an attack on them is known.",
"examples": "An intelligence agency archiving chain data today, then anyone once a break is public."
}
],
"fields": [
{
"id": "sender",
"label": "Sender",
"subject": "Sender",
"promiseLabel": "Sender privacy",
"description": "The Ethereum address that funds entered from, or that initiated a transfer."
},
{
"id": "recipient",
"label": "Recipient",
"subject": "Recipient",
"promiseLabel": "Recipient privacy",
"description": "Who receives the funds: the address they exit to, the receiver of a transfer, or whoever controls a one-time receiving address."
},
{
"id": "amount",
"label": "Amount",
"subject": "Amounts",
"promiseLabel": "Amount privacy",
"description": "The value moved."
},
{
"id": "asset",
"label": "Asset",
"subject": "Asset",
"promiseLabel": "Asset privacy",
"description": "Which token is moved."
},
{
"id": "linkage",
"label": "Link",
"subject": "Link",
"promiseLabel": "Link privacy",
"description": "Whether the entry and exit of the same funds, or sender and recipient of the same transfer, can be tied together."
}
],
"cells": {
"publicObserver": {
"sentiment": "good",
"exposureShort": "Zcash's shielded pool hides which payout into it funds which later exit.",
"exposureContinued": "Everything up to the pool edge is public: the Ethereum deposit and the NEAR entries that credit, swap and withdraw it. The bridge encrypts each payout so that anyone can decrypt its Zcash address and amount.",
"interior": {
"sender": "private",
"recipient": {
"verdict": "atRisk",
"note": "Payout notes are decryptable by anyone, so a reused address ties payouts together."
},
"amount": "private",
"asset": {
"verdict": "exposed",
"note": "Only ZEC exists inside the pool. The assets swapped from and to are public on NEAR."
},
"linkage": "private"
},
"sources": [
{
"title": "Custodial bridge mint carries the Ethereum transaction hash in its memo",
"url": "https://nearblocks.io/address/eth.omft.near"
},
{
"title": "Withdrawal message names the target Zcash address",
"url": "https://github.com/Near-One/btc-bridge/blob/4711c2f1d035a208464b9729bb24e45ed9ab7831/contracts/satoshi-bridge/src/api/token_receiver.rs#L8-L16"
},
{
"title": "Payouts are encrypted to an all-zero outgoing viewing key",
"url": "https://github.com/Near-One/btc-bridge/blob/4711c2f1d035a208464b9729bb24e45ed9ab7831/contracts/satoshi-bridge/src/zcash_utils/orchard_policy.rs#L13-L63"
},
{
"title": "Zodl creates a fresh shielded address for every quote",
"url": "https://github.com/zodl-inc/zodl-ios/blob/75b83d7601573e165e2dacdfaffb69750dadd05f/secant/Sources/Features/SwapAndPayForm/SwapAndPayStore.swift#L908-L955"
}
],
"id": "publicObserver",
"value": "Link private",
"alsoExposed": []
},
"chainAnalyst": {
"sentiment": "good",
"exposureShort": "Only the amount and timing of a round trip can pair a payout into the pool with a later deposit to the bridge.",
"exposureContinued": "Deposit addresses are fresh per quote and spent together with the bridge change address, which marks every exit as NEAR Intents.",
"advice": "Hold the ZEC in the pool for days, split or merge it with other shielded funds, and swap back amounts that match no payout.",
"interior": {
"sender": "private",
"recipient": {
"verdict": "atRisk",
"note": "Payout notes are decryptable by anyone, so a reused address ties payouts together."
},
"amount": "private",
"asset": "exposed",
"linkage": {
"verdict": "atRisk",
"note": "Round-trip amount and timing across the pool edge pair a payout with a later deposit."
}
},
"sources": [
{
"title": "Kappos et al., An Empirical Analysis of Anonymity in Zcash (USENIX 2018)",
"url": "https://arxiv.org/abs/1805.03180"
},
{
"title": "Deposit address derived per quote from the deposit message",
"url": "https://github.com/Near-One/btc-bridge/blob/4711c2f1d035a208464b9729bb24e45ed9ab7831/contracts/satoshi-bridge/src/deposit_msg.rs#L49-L52"
},
{
"title": "Bridge change address and UTXO set",
"url": "https://nearblocks.io/address/zcash-connector.bridge.near"
}
],
"id": "chainAnalyst",
"value": "Link private",
"alsoExposed": []
},
"networkObserver": {
"sentiment": "warning",
"exposureShort": "Each sync sends the user's transparent addresses to lightwalletd outside Tor, tying both the payout fetch and the exit to that user by timing.",
"exposureContinued": "Zodl's Tor isolates each 1Click request, payout fetch and transaction, while block sync and these address lookups stay direct.",
"advice": "Turn on Tor in Zodl and point it at a lightwalletd server the user runs.",
"interior": {
"sender": "private",
"recipient": "private",
"amount": "private",
"asset": "exposed",
"linkage": {
"verdict": "atRisk",
"note": "Private only with Tor on and the user's own lightwalletd server."
}
},
"sources": [
{
"title": "Tor is off unless the user enables it",
"url": "https://github.com/zodl-inc/zodl-ios/blob/75b83d7601573e165e2dacdfaffb69750dadd05f/secant/Sources/Dependencies/SDKSynchronizer/SDKSynchronizerLive.swift#L45"
},
{
"title": "Every sync looks up the account's transparent addresses directly",
"url": "https://github.com/zodl-inc/zodl-swift-wallet-sdk/blob/191d0347186a1c6fcd207eead24a891049444041/Sources/ZcashLightClientKit/Block/FetchUnspentTxOutputs/UTXOFetcher.swift#L39-L52"
},
{
"title": "Each transaction fetch and send gets its own Tor connection",
"url": "https://github.com/zodl-inc/zodl-swift-wallet-sdk/blob/191d0347186a1c6fcd207eead24a891049444041/Sources/ZcashLightClientKit/Modules/Service/LightWalletService.swift#L146-L159"
},
{
"title": "Compact blocks download over a direct connection",
"url": "https://github.com/zodl-inc/zodl-swift-wallet-sdk/blob/191d0347186a1c6fcd207eead24a891049444041/Sources/ZcashLightClientKit/Block/Download/BlockDownloader.swift#L187"
}
],
"id": "networkObserver",
"value": "Link at risk",
"alsoExposed": []
},
"privilegedInsider": {
"sentiment": "bad",
"exposureShort": "The operator custodies both legs in transit and can freeze any account or deposit, setting the terms on which the user's funds return.",
"exposureContinued": "Over Tor, its 1Click API sees each leg only as NEAR publishes it, with a fresh shielded address per swap. It holds no key into the shielded pool.",
"interior": {
"sender": "private",
"recipient": "private",
"amount": "private",
"asset": "exposed",
"linkage": {
"verdict": "atRisk",
"note": "The operator can freeze either leg and set the terms of its release."
}
},
"sources": [
{
"title": "1Click terms: IP and wallet data, screening, custody",
"url": "https://docs.near-intents.org/security-compliance/terms-of-service"
},
{
"title": "Any account can be locked by the multisig or a locker",
"url": "https://github.com/near/intents/blob/fa44ede9e874931c39a6c4246de82bc40f4f8d99/defuse/src/contract/accounts/force.rs#L21-L33"
},
{
"title": "Owner-only mint of the wrapped Ethereum assets",
"url": "https://github.com/near/intents/blob/fa44ede9e874931c39a6c4246de82bc40f4f8d99/poa-token/src/contract.rs#L79-L81"
},
{
"title": "Zodl sends its partner key and a fresh refund address with each quote",
"url": "https://github.com/zodl-inc/zodl-ios/blob/75b83d7601573e165e2dacdfaffb69750dadd05f/secant/Sources/Dependencies/SwapAndPay/sources/Near1Click.swift#L313-L352"
}
],
"id": "privilegedInsider",
"value": "Link exposed",
"alsoExposed": []
},
"futureAdversary": {
"sentiment": "bad",
"exposureShort": "All of an account's rotated addresses share one incoming viewing key on the Pallas curve, and every payout address is public on NEAR.",
"exposureContinued": "Whoever breaks elliptic-curve cryptography recovers that key from any one address and decrypts every note the account ever received. Those include the change notes of its exits, which join both legs of every round trip. ZIP 2005's quantum recoverability protects only funds.",
"interior": {
"sender": {
"verdict": "atRisk",
"note": "Spends are found through the change notes they pay back to the same account."
},
"recipient": "exposed",
"amount": "exposed",
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "Orchard key agreement on the Pallas curve",
"url": "https://zips.z.cash/protocol/protocol.pdf#concreteorchardkeyagreement"
},
{
"title": "ZIP 2005: quantum recoverability of funds",
"url": "https://zips.z.cash/zip-2005"
},
{
"title": "Payouts are encrypted to an all-zero outgoing viewing key",
"url": "https://github.com/Near-One/btc-bridge/blob/4711c2f1d035a208464b9729bb24e45ed9ab7831/contracts/satoshi-bridge/src/zcash_utils/orchard_policy.rs#L13-L63"
}
],
"id": "futureAdversary",
"value": "Link exposed",
"alsoExposed": [
{
"field": "sender",
"exposure": "atRisk"
},
{
"field": "recipient",
"exposure": "exposed"
},
{
"field": "amount",
"exposure": "exposed"
}
]
}
}
},
"anonymitySet": {
"type": "not-applicable",
"description": "The set is Zcash's shielded pool, outside the chains L2BEAT indexes. Amounts are public at the pool edge, so an exit hides among the pool entries that could match it in amount and time."
},
"attributes": [
{
"id": "bridged",
"label": "Bridged",
"description": "Funds leave Ethereum through a bridge and gain their privacy on another chain."
},
{
"id": "zk",
"label": "ZK",
"description": "Uses zero-knowledge proofs to prove private actions without revealing private data."
},
{
"id": "transfers",
"label": "Transfers",
"description": "Private transfers within the shielded pool."
},
{
"id": "anyAmount",
"label": "Any amount",
"description": "Deposits and withdrawals can have any size."
}
],
"category": {
"id": "shieldedLedger",
"label": "Shielded ledger",
"description": "A pool with transfers or DeFi inside. Hides who pays whom and which deposit became which withdrawal."
},
"exitWindow": {
"value": "None",
"sentiment": "bad",
"orderHint": 0,
"description": "The NEAR Intents multisig upgrades the Verifier and the Rainbow Bridge multisig the Zcash bridge, both instantly. The Ethereum funds sit in an EOA the operator controls.",
"walkawayTest": {
"passed": false,
"reason": "The custodial bridge operator executes every Ethereum deposit and withdrawal offchain. For the Zcash light client on NEAR, anyone staking 1,000 NEAR can relay after seven days, unless the Rainbow Bridge multisig rejects them."
}
},
"reproducibility": {
"value": "Partially reproducible",
"sentiment": "warning",
"description": "The Verifier, the bridge token, the Zcash bridge and Zodl are open source. The bridge back end, the 1Click API and the solver relay that every Ethereum leg needs are closed."
},
"riskSummary": "## Funds can be stolen if\n1. the custodial bridge operator's mint key or its Ethereum treasury key is compromised.\n2. the NEAR Intents multisig upgrades the Verifier maliciously.\n3. the Rainbow Bridge multisig upgrades the Zcash connector, its token or the light client maliciously.\n4. a threshold of the NEAR MPC nodes colludes to sign Zcash transactions from bridge addresses.\n
\n## Funds can be frozen if\n1. the NEAR Intents multisig or the single-key account locker freezes the user's account in the Verifier.\n2. the custodial bridge operator holds a deposit or withdrawal for a compliance review.\n3. the relayers stop and the Rainbow Bridge multisig rejects anyone who stakes to replace them.\n
\n## Privacy can be lost if\n1. the operator, which custodies both legs, makes the release of either depend on who the user is (see privileged insider).\n2. the lightwalletd server Zodl syncs from ties the payout and the exit to the account, since syncs send transparent addresses outside Tor (see network observer).\n3. elliptic-curve cryptography is broken, which recovers each account's viewing key from its payout addresses on NEAR (see future adversary).",
"tokens": [],
"trackedOn": [
"ethereum"
],
"upgradesAndGovernance": {
"content": "The route touches three governed systems on NEAR, each can change instantly. The Ethereum side runs on EOAs.\n\n### NEAR Intents Verifier (`intents.near`)\n\n`intents.sputnik-dao.near`, a 3/5 multisig, holds the `DAO` role and is super admin, so it can grant every other role. Upgrades go through `ctl-intents.near`, a controller whose only admin is the same multisig, and deploy at once. Six accounts hold `PauseManager` and can halt all swaps and withdrawals, and only the multisig can resume them. One EOA holds `UnrestrictedAccountLocker` and can lock any user account. A locked account keeps receiving deposits, while its intents and withdrawals stop until the multisig unlocks it.\n\n### Custodial \"PoA\" bridge (`omft.near`, `eth.omft.near`)\n\nThe `poa-factory` contract `omft.near` deploys one token per bridged asset. It mints on the signal of `TokenDepositer`: `bridge-mng.near`, an EOA, and `int-mnt-dao.sputnik-dao.near`, a 3/3 multisig. NEAR takes every mint on trust. The NEAR Intents multisig is super admin.\n\n### Zcash connector (`zcash-connector.bridge.near`, `zec.omft.near`, `zcash-client.bridge.near`)\n\n`rainbowbridge.sputnik-dao.near`, a 3/5 multisig, governs the connector, the token's controller and the light client, and sets the bridge fees. `bridge-ops.near` can stage code and pause the connector, and `pm.bridge.near` can pause it. `omni-relayer.bridge.near` and `intents-relayer.near` prove deposits against the light client, whose headers `zcash-relayer.near` relays. Withdrawals are signed by the NEAR MPC network `v1.signer` (11/17, see the [MPC operators page](https://mpc-operators.nearone.org/)) on request of a relayer. These three hold roles that make them relayers. Anyone else becomes one after staking 1,000 NEAR and waiting seven days, and the multisig can reject any relayer. Anyone can refund a deposit the connector never credited, once the light client holds its block. The refund waits two days, or fourteen when the deposit message names no refund address. The multisig or `omni-relayer.bridge.near` can reject the refund until then."
},
"zkCatalogId": "zcash"
}
+9 -14
+9 -14
{
"adversaries": {
"promise": {
"protects": "linkage",
"text": "Hides which deposit pays for which API request. Deposits and withdrawals are public, and the provider can read prompts."
},
"adversaries": [
{
"id": "publicObserver",
"label": "Public observer",
"description": "Everyone with a block explorer and some basic tools. Sees every public onchain event, but does no correlation beyond following links.",
"examples": "A curious counterparty, an employer, a journalist."
},
{
"id": "chainAnalyst",
"label": "Chain analyst",
"description": "Scrapes all public data and correlates it: timing, amounts, gas and wallet fingerprints, address clusters.",
"examples": "Chain analytics firms, ZachXBT, data brokers."
},
{
"id": "networkObserver",
"label": "Network observer",
"description": "Sits between the user and the services and sees traffic only: ISPs, VPNs, Tor exits, public RPCs and relayers. Learns IP addresses, timing, fingerprints and ciphertext. Services the operator runs count as the insider.",
"examples": "Infura or Alchemy, a Tornado relayer, a wallet vendor selling telemetry, Google captcha or analytics in the dapp frontend."
},
{
"id": "privilegedInsider",
"label": "Privileged insider",
"description": "Holds an operator role, custodies funds, receives keys or plaintext by design, or delivers the client: upgrade admin, custodian, view key holder, enclave operator, association set provider, hosted prover, registry, frontend host.",
"examples": "A compliance backdoor key, a DAO with an upgrade key, a KMS committee, an ASP operator, a custodial bridge."
},
{
"id": "futureAdversary",
"label": "Future adversary",
"description": "Harvest now, decrypt later. Holds every byte ever written onchain plus any retained logs, and breaks all public-key cryptography, by quantum computer or new mathematics: elliptic curves, pairings, RSA, lattices and isogenies. Hashes, Poseidon included, and symmetric ciphers survive.",
"description": "Harvest now, decrypt later. Holds every byte ever published and runs the known quantum attacks: elliptic curves, pairings and RSA fall. Hashes, symmetric ciphers and post-quantum schemes stand until an attack on them is known.",
"examples": "An intelligence agency archiving chain data today, then anyone once a break is public."
}
],
"fields": [
{
"id": "sender",
"label": "Sender",
"subject": "Sender",
"promiseLabel": "Sender privacy",
"description": "The Ethereum address that funds entered from, or that initiated a transfer."
},
{
"id": "recipient",
"label": "Recipient",
"subject": "Recipient",
"promiseLabel": "Recipient privacy",
"description": "Who receives the funds: the address they exit to, the receiver of a transfer, or whoever controls a one-time receiving address."
},
{
"id": "amount",
"label": "Amount",
"subject": "Amounts",
"promiseLabel": "Amount privacy",
"description": "The value moved."
},
{
"id": "asset",
"label": "Asset",
"subject": "Asset",
"promiseLabel": "Asset privacy",
"description": "Which token is moved."
},
{
"id": "linkage",
"label": "Link",
"subject": "Link",
"promiseLabel": "Link privacy",
"description": "Whether an API request can be tied to the deposit that pays for it."
}
],
"cells": {
"publicObserver": {
"sentiment": "good",
"exposureShort": "Requests stay offchain, so nothing onchain ties a request to the deposit that pays for it.",
"exposureContinued": "A deposit publishes the funder, amount, note id and expiry. Closing the note publishes the payout address and the remaining balance, so each note's total spend is public.",
"interior": {
"sender": "exposed",
"recipient": {
"verdict": "exposed",
"note": "Payments go to the operator treasury."
},
"amount": {
"verdict": "atRisk",
"note": "Charges per request stay offchain. Closing the note publishes the total."
},
"asset": "exposed",
"linkage": {
"verdict": "private",
"note": "An escape dispute publishes the link for one request."
}
},
"sources": [
{
"contract": "ZkApiVault"
},
{
"title": "Deposit and close events",
"url": "https://github.com/ethereum/zkapi/blob/045b444ea1b52538d1b40273c7cb6ed09468a052/protocol/contracts/src/libraries/Events.sol#L6-L10"
},
{
"title": "Request circuit keeps note id, balance and state signature private",
"url": "https://github.com/ethereum/zkapi/blob/045b444ea1b52538d1b40273c7cb6ed09468a052/protocol/rust/crates/zkapi-proof/src/groth16.rs#L368-L485"
}
],
"id": "publicObserver",
"value": "Link private",
"alsoExposed": []
},
"chainAnalyst": {
"sentiment": "good",
"exposureShort": "Authorizations never reach the chain, so correlating public data adds nothing to the note record.",
"interior": {
"sender": "exposed",
"recipient": {
"verdict": "exposed",
"note": "Payments go to the operator treasury."
},
"amount": {
"verdict": "atRisk",
"note": "Charges per request stay offchain. Closing the note publishes the total."
},
"asset": "exposed",
"linkage": {
"verdict": "private",
"note": "An escape dispute publishes the link for one request."
}
},
"sources": [
{
"title": "Authorization is an HTTP request to the operator",
"url": "https://github.com/ethereum/zkapi/blob/045b444ea1b52538d1b40273c7cb6ed09468a052/docs/api-spec.md"
}
],
"id": "chainAnalyst",
"value": "Link private",
"alsoExposed": []
},
"networkObserver": {
"sentiment": "good",
"exposureShort": "The app works in Tor Browser, the daemon has a Tor setting with a kill switch, and no third party sees both a deposit and a request.",
"exposureContinued": "The RPC serving the user's wallet sees the deposit, while requests go to the operator and the provider. The app sends inference through a relay at refraction.network by default, which sees its timing. The hosted app reports feature use to Fathom, a cookieless analytics service.",
"advice": "Use the app in Tor Browser, or the daemon with its Tor setting, and send the deposit through a public RPC over Tor.",
"interior": {
"sender": "exposed",
"recipient": {
"verdict": "exposed",
"note": "Payments go to the operator treasury."
},
"amount": {
"verdict": "atRisk",
"note": "Charges per request stay offchain. Closing the note publishes the total."
},
"asset": "exposed",
"linkage": {
"verdict": "atRisk",
"note": "Private only over Tor, which keeps the user's IP off both sides."
}
},
"sources": [
{
"title": "Daemon Tor route has a kill switch",
"url": "https://github.com/ethereum/zkapi/blob/045b444ea1b52538d1b40273c7cb6ed09468a052/zkapi-clientd/docs/CLI_ZKAPI.md#L81-L97"
},
{
"title": "App relay on by default, direct fallback",
"url": "https://github.com/OpenAnonymity/oa-chat/blob/60ed5be2957d984c70a7299474927becec47b61f/chat/services/networkProxy.js#L7-L10"
},
{
"title": "Hosted app loads Fathom Analytics (checked 2026-10-10)",
"url": "https://chat.openanonymity.ai"
}
],
"id": "networkObserver",
"value": "Link private",
"alsoExposed": []
},
"privilegedInsider": {
"sentiment": "warning",
"exposureShort": "The operator sees each request's time and budget but not its note, so the candidates are all active notes, a small set.",
"exposureContinued": "The daemon reveals the note id to the operator's indexer before each request. An escape dispute lets the operator publish one request's link onchain. The provider can read prompts and responses and link requests under one key.",
"advice": "Use the browser app rather than the daemon, and wait a day or more between depositing and the user's first request. Run an inspected local build of the client instead of the hosted frontend.",
"interior": {
"sender": "exposed",
"recipient": "exposed",
"amount": {
"verdict": "exposed",
"note": "The operator bills each request and the provider meters it."
},
"asset": "exposed",
"linkage": {
"verdict": "atRisk",
"note": "Timing narrows a small set, and daemon users reveal the note id."
}
},
"sources": [
{
"title": "Balance commitment re-blinded for every request",
"url": "https://github.com/ethereum/zkapi/blob/045b444ea1b52538d1b40273c7cb6ed09468a052/docs/note-bound-commitments.md"
},
{
"title": "Daemon fetches the note path by note id",
"url": "https://github.com/ethereum/zkapi/blob/20aa542ae98e767c0507133fd34b12a56f5ccd3d/crates/zkapi-clientd/src/indexer.rs#L71-L80"
},
{
"contract": "ZkApiVault",
"title": "challengeEscapeWithdrawal publishes a request proof"
},
{
"title": "Provider sees inference content",
"url": "https://github.com/ethereum/zkapi/blob/045b444ea1b52538d1b40273c7cb6ed09468a052/zkapi-clientd/docs/PRIVACY.md"
}
],
"id": "privilegedInsider",
"value": "Link at risk",
"alsoExposed": [
{
"field": "amount",
"exposure": "exposed"
}
]
},
"futureAdversary": {
"sentiment": "warning",
"exposureShort": "Onchain data stays hashed, but retained operator transcripts and indexer logs would tie requests to deposits.",
"exposureContinued": "Note leaves and nullifiers are Poseidon hashes. Whoever breaks elliptic-curve cryptography opens only the balance commitment that a published dispute carries.",
"advice": "Assume the operator and provider keep what the user sends.",
"sentiment": "good",
"exposureShort": "Note leaves and nullifiers are Poseidon hashes and nothing encrypted is written onchain, so there is nothing to decrypt.",
"exposureContinued": "Whoever breaks elliptic-curve cryptography opens only the balance commitment that a published dispute carries.",
"interior": {
"sender": "exposed",
"recipient": {
"verdict": "exposed",
"note": "Payments go to the operator treasury."
},
"amount": {
"verdict": "atRisk",
"note": "Per-request charges exist only in operator records."
"note": "Charges per request stay offchain. Closing the note publishes the total."
},
"asset": "exposed",
"linkage": {
"verdict": "atRisk",
"note": "Depends on what the operator retains."
"verdict": "private",
"note": "An escape dispute publishes the link for one request."
}
},
"sources": [
{
"title": "Transcript store",
"url": "https://github.com/ethereum/zkapi/blob/045b444ea1b52538d1b40273c7cb6ed09468a052/crates/zkapi-serverd/src/nullifier_store.rs"
},
{
"title": "Note-bound commitments and assumptions",
"url": "https://github.com/ethereum/zkapi/blob/045b444ea1b52538d1b40273c7cb6ed09468a052/docs/note-bound-commitments.md"
}
],
"id": "futureAdversary",
"value": "Link at risk",
"value": "Link private",
"alsoExposed": []
}
}
},
"attributes": [
{
"id": "zk",
"label": "ZK",
"description": "Uses zero-knowledge proofs to prove private actions without revealing private data."
},
{
"id": "anyAmount",
"label": "Any amount",
"description": "Deposits and withdrawals can have any size."
}
],
"category": {
"id": "anonymousAccess",
"label": "Anonymous access",
"description": "Proves eligibility to use a service without revealing which account or deposit grants access."
},
"exitWindow": {
"value": "None",
"sentiment": "bad",
"orderHint": 0,
"description": "The owner can immediately pause cooperative closes and the start of escapes. An already pending escape can be finalized after 1 day, including during a pause. An active note becomes sweepable after its deposit expiry.",
"walkawayTest": {
"passed": false,
"reason": "Starting an escape needs an unpaused vault and the user's latest signed balance. The operator can cancel it with any request proof it holds for that balance, and only a new operator signature restores normal use."
}
},
"reproducibility": {
"value": "Partially reproducible",
"sentiment": "warning",
"description": "The browser app and the local daemon have public source and build instructions. The verifier enclave image rebuilds from source and matches its hardware attestation. The hosted frontend, the daemon releases and the key stations remain unreproduced."
},
"riskSummary": "## Funds can be stolen if\n\n1. the owner pauses withdrawals until notes expire and anyone sweeps them to its treasury.\n2. the single-party setup secrets or a circuit flaw allow forged withdrawal proofs.\n3. malicious wallet code reads the note secret.\n\n
\n\n## Funds can be lost or frozen if\n\n1. the note secret or the latest signed balance is lost.\n2. a note expires before withdrawal.\n3. the operator withholds a signed balance and cancels the escape with the request it received.\n\n
\n\n## Privacy can be lost if\n\n1. the operator matches a deposit to its requests by timing, which few active notes make easy (see privileged insider).\n2. a daemon user reveals the note id to the operator's indexer before each request (see privileged insider).\n3. prompts identify the user to OpenRouter or the model provider (see privileged insider).\n4. the operator keeps request transcripts and indexer logs, which later tie requests to deposits (see future adversary).",
"riskSummary": "## Funds can be stolen if\n\n1. the owner pauses withdrawals until notes expire and anyone sweeps them to its treasury.\n2. the single-party setup secrets or a circuit flaw allow forged withdrawal proofs.\n3. malicious wallet code reads the note secret.\n\n
\n\n## Funds can be lost or frozen if\n\n1. the note secret or the latest signed balance is lost.\n2. a note expires before withdrawal.\n3. the operator withholds a signed balance and cancels the escape with the request it received.\n\n
\n\n## Privacy can be lost if\n\n1. the operator matches a deposit to its requests by timing, which few active notes make easy (see privileged insider).\n2. a daemon user reveals the note id to the operator's indexer before each request (see privileged insider).\n3. prompts identify the user to OpenRouter or the model provider (see privileged insider).\n4. the operator keeps request transcripts and indexer logs, which later tie requests to deposits (see privileged insider).",
"tokens": [
{
"token": {
"address": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
"iconUrl": "https://assets.coingecko.com/coins/images/279/large/ethereum.png?1595348880",
"symbol": "ETH",
"decimals": 18,
"priceId": "ethereum",
"sinceTimestamp": 1790783879
},
"buckets": [
{
"id": "zkapi-ETH",
"type": "pool",
"label": "ETH API balances",
"address": "eth:0x4386FDbdA35D995beB3BF8625118Ec5982ec81fe",
"sinceTimestamp": 1790783879,
"deposit": {
"event": "0x7c83dba8534bea9e30d6444f9ca6462dc906897f9938d220dbbe4358c1f7a063",
"extractor": "zkApiDeposit",
"params": {
"weiPerUnit": "1000000000"
}
},
"withdrawal": {
"event": "0x1f43fa4711ca18e1d26398f26bf598bd3a62992cdd0e84f055f2bb506e9d7031",
"extractor": "zkApiWithdrawal",
"params": {
"weiPerUnit": "1000000000"
}
},
"additionalWithdrawals": [
{
"event": "0x163f2e46c4004f0ed9682e2db8c84efac31310720266b17ea9904ba348c26504",
"extractor": "zkApiWithdrawal",
"params": {
"weiPerUnit": "1000000000"
}
}
]
}
]
}
],
"trackedOn": [
"ethereum"
],
"upgradesAndGovernance": {
"content": "The vault, verifier, signing keys and exit parameters are immutable. The owner EOA can set the treasury, pause deposits, cooperative closes and the start of escapes, and transfer or renounce ownership, all without delay. Pending escapes still finalize during a pause. An instant pause with a subsequent sweep after expiry would steal all funds whose escape was not started before the pause.\n\nThe operator's services, the hosted app and the daemon releases are controlled by Open Anonymity and can change without notice."
}
}
+1 -1
+1 -1
{
"adversaries": {
"promise": {
"protects": "linkage",
"text": "Hides senders, amounts and the link between deposits and withdrawals inside the ledger. Names, deposits and withdrawals are public."
},
"adversaries": [
{
"id": "publicObserver",
"label": "Public observer",
"description": "Everyone with a block explorer and some basic tools. Sees every public onchain event, but does no correlation beyond following links.",
"examples": "A curious counterparty, an employer, a journalist."
},
{
"id": "chainAnalyst",
"label": "Chain analyst",
"description": "Scrapes all public data and correlates it: timing, amounts, gas and wallet fingerprints, address clusters.",
"examples": "Chain analytics firms, ZachXBT, data brokers."
},
{
"id": "networkObserver",
"label": "Network observer",
"description": "Sits between the user and the services and sees traffic only: ISPs, VPNs, Tor exits, public RPCs and relayers. Learns IP addresses, timing, fingerprints and ciphertext. Services the operator runs count as the insider.",
"examples": "Infura or Alchemy, a Tornado relayer, a wallet vendor selling telemetry, Google captcha or analytics in the dapp frontend."
},
{
"id": "privilegedInsider",
"label": "Privileged insider",
"description": "Holds an operator role, custodies funds, receives keys or plaintext by design, or delivers the client: upgrade admin, custodian, view key holder, enclave operator, association set provider, hosted prover, registry, frontend host.",
"examples": "A compliance backdoor key, a DAO with an upgrade key, a KMS committee, an ASP operator, a custodial bridge."
},
{
"id": "futureAdversary",
"label": "Future adversary",
"description": "Harvest now, decrypt later. Holds every byte ever written onchain plus any retained logs, and breaks all public-key cryptography, by quantum computer or new mathematics: elliptic curves, pairings, RSA, lattices and isogenies. Hashes, Poseidon included, and symmetric ciphers survive.",
"description": "Harvest now, decrypt later. Holds every byte ever published and runs the known quantum attacks: elliptic curves, pairings and RSA fall. Hashes, symmetric ciphers and post-quantum schemes stand until an attack on them is known.",
"examples": "An intelligence agency archiving chain data today, then anyone once a break is public."
}
],
"fields": [
{
"id": "sender",
"label": "Sender",
"subject": "Sender",
"promiseLabel": "Sender privacy",
"description": "The Ethereum address that funds entered from, or that initiated a transfer."
},
{
"id": "recipient",
"label": "Recipient",
"subject": "Recipient",
"promiseLabel": "Recipient privacy",
"description": "Who receives the funds: the address they exit to, the receiver of a transfer, or whoever controls a one-time receiving address."
},
{
"id": "amount",
"label": "Amount",
"subject": "Amounts",
"promiseLabel": "Amount privacy",
"description": "The value moved."
},
{
"id": "asset",
"label": "Asset",
"subject": "Asset",
"promiseLabel": "Asset privacy",
"description": "Which token is moved."
},
{
"id": "linkage",
"label": "Link",
"subject": "Link",
"promiseLabel": "Link privacy",
"description": "Whether the entry and exit of the same funds, or sender and recipient of the same transfer, can be tied together."
}
],
"cells": {
"publicObserver": {
"sentiment": "good",
"exposureShort": "Private payments publish encrypted notes.",
"exposureContinued": "Claiming a name ties it and its Aztec address to the wallet that funds the registration. The first payment to a new contact reveals the recipient through a handshake, and L2 logs mark every transaction of the shared token smart contract. The user's first sponsored transaction after registration is tied to their account, with the payment, deposit address or withdrawal it carries.",
"advice": "Claim the user's name from a wallet without a public link to them, then make the first transaction after registration a deposit from that wallet. Fund each deposit address once and let it be swept/relayed.",
"interior": {
"sender": {
"verdict": "atRisk",
"note": "Public for the user's first sponsored transaction after registration."
},
"recipient": {
"verdict": "exposed",
"note": "Revealed by the first payment to each new contact."
},
"amount": "private",
"asset": {
"verdict": "exposed",
"note": "Only DAI."
},
"linkage": {
"verdict": "atRisk",
"note": "Exposed when the user's first sponsored transaction after registration withdraws or pays a new contact."
}
},
"sources": [
{
"title": "Fixed log tags on every token transaction",
"url": "https://github.com/aztec-labs-eng/zkmoney-public/blob/f04743f5d57d1b89f9190cad0f6affd28b0793f2/vendor/oxide/noir-projects/oxide_lib/src/constants.nr#L77-L81"
},
{
"title": "First delivery to a new contact opens a handshake",
"url": "https://github.com/aztec-labs-eng/zkmoney-public/blob/f04743f5d57d1b89f9190cad0f6affd28b0793f2/packages/sdk/src/feePaymentMethod/claimFpcGasModel.ts#L232-L237"
},
{
"title": "First sponsored transaction nullifies the L1 account",
"url": "https://github.com/aztec-labs-eng/zkmoney-public/blob/f04743f5d57d1b89f9190cad0f6affd28b0793f2/packages/contracts/contracts/fee_paying/claim_fpc/src/main.nr#L205-L217"
},
{
"contract": "AccountMetadataRegistry",
"title": "Names map to Aztec addresses"
}
],
"id": "publicObserver",
"value": "Link private",
"alsoExposed": []
},
"chainAnalyst": {
"sentiment": "warning",
"exposureShort": "In practice the anonymity set is zk.money's users on Aztec, although the L2 contract is permissionless.",
"exposureContinued": "The first payment to a name from outside zk.money is publicly tied to that name.",
"advice": "Give outside payers a deposit address the user's wallet created. Withdraw common amounts rather than everything at once. Wait before exiting and pick a different time of day than the deposit. Exit to a fresh address every time and spend from it with a different wallet than the one that deposited.",
"interior": {
"sender": {
"verdict": "atRisk",
"note": "Public for the user's first sponsored transaction after registration."
},
"recipient": {
"verdict": "exposed",
"note": "Revealed by the first payment to each new contact."
},
"amount": {
"verdict": "atRisk",
"note": "Inferable when a payment sits between a matching public deposit and withdrawal."
},
"asset": {
"verdict": "exposed",
"note": "Only DAI."
},
"linkage": {
"verdict": "atRisk",
"note": "Registration deposits are publicly tied to their name."
}
},
"sources": [
{
"contract": "RegistrationSIPA"
},
{
"title": "Resolver notifies the recipient of each deposit address",
"url": "https://github.com/aztec-labs-eng/zkmoney-public/blob/f04743f5d57d1b89f9190cad0f6affd28b0793f2/vendor/oxide/noir-projects/oxide_token_contract/src/main.nr#L236-L251"
},
{
"title": "The notification and the sweep request share one Aztec transaction",
"url": "https://github.com/aztec-labs-eng/zkmoney-public/blob/f04743f5d57d1b89f9190cad0f6affd28b0793f2/packages/sdk/src/services/sipaIntents.ts#L171-L186"
},
{
"title": "Handshake announcements are tagged with the recipient address",
"url": "https://github.com/AztecProtocol/aztec-packages/blob/v5.2.0/noir-projects/noir-contracts/contracts/standard/handshake_registry_contract/src/main.nr#L82-L96"
}
],
"id": "chainAnalyst",
"value": "Link at risk",
"alsoExposed": [
{
"field": "amount",
"exposure": "atRisk"
}
]
},
"networkObserver": {
"sentiment": "warning",
"exposureShort": "Anyone on the user's network path sees their Aztec transactions and can match their deposit and withdrawal to the blocks they land in.",
"exposureContinued": "Desktop has no Tor or proxy setting.",
"advice": "Route zk.money Desktop through Tor with system-wide tools.",
"interior": {
"sender": {
"verdict": "atRisk",
"note": "XMTP shows who asks whom for payment."
},
"recipient": {
"verdict": "exposed",
"note": "Revealed by the first payment to each new contact."
},
"amount": "private",
"asset": {
"verdict": "exposed",
"note": "Only DAI."
},
"linkage": {
"verdict": "atRisk",
"note": "Private only over Tor, which Desktop lacks."
}
},
"sources": [
{
"title": "Desktop settings: endpoints only, no proxy",
"url": "https://github.com/aztec-labs-eng/zkmoney-public/blob/f04743f5d57d1b89f9190cad0f6affd28b0793f2/packages/web-wallet-desktop/src/config.js#L36-L47"
},
{
"title": "XMTP identity is the account bootstrap address",
"url": "https://github.com/aztec-labs-eng/zkmoney-public/blob/f04743f5d57d1b89f9190cad0f6affd28b0793f2/packages/web-wallet/src/platform/xmtp/WebXmtpClient.ts#L95-L109"
}
],
"id": "networkObserver",
"value": "Link at risk",
"alsoExposed": []
},
"privilegedInsider": {
"sentiment": "bad",
"exposureShort": "The wallets derive their own deposit addresses from an ECDH secret shared with the resolver operator, Aztec Labs today.",
"exposureContinued": "Matching the derived commitments against public portal deposits lets the operator link L1 deposits to L2 recipients. Payments, withdrawals and deposit claims are encrypted to an enclave admitted with an AWS Nitro attestation, which reads them inside.",
"interior": {
"sender": "exposed",
"recipient": "exposed",
"amount": "exposed",
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"title": "Wallets derive deposit addresses against the resolver key",
"url": "https://github.com/aztec-labs-eng/zkmoney-public/blob/f04743f5d57d1b89f9190cad0f6affd28b0793f2/packages/web-wallet/src/features/deposit/sipaGateway.ts#L857-L871"
},
{
"title": "Their nonces count down a predictable range",
"url": "https://github.com/aztec-labs-eng/zkmoney-public/blob/f04743f5d57d1b89f9190cad0f6affd28b0793f2/packages/sdk/src/services/sipaSelfResolve.ts#L49-L58"
},
{
"title": "Wallets encrypt to the enclave key registered in the portal",
"url": "https://github.com/aztec-labs-eng/zkmoney-public/blob/f04743f5d57d1b89f9190cad0f6affd28b0793f2/vendor/oxide/yarn-project/oxide-client/src/fleet_signer.ts#L172-L202"
},
{
"contract": "ZkMoneyPortal",
"title": "Deposits publish the recipient commitment"
}
],
"id": "privilegedInsider",
"value": "Link exposed",
"alsoExposed": [
{
"field": "sender",
"exposure": "exposed"
},
{
"field": "amount",
"exposure": "exposed"
}
]
},
"futureAdversary": {
"sentiment": "bad",
"exposureShort": "Whoever breaks elliptic-curve cryptography can decrypt historical notes and payment events published to Ethereum.",
"exposureContinued": "Registered Aztec addresses identify the accounts. Deposit address secrets and enclave communication use the same class of cryptography.",
"interior": {
"sender": "exposed",
"recipient": "exposed",
"amount": "exposed",
"asset": "exposed",
"linkage": "exposed"
},
"sources": [
{
"contract": "AccountMetadataRegistry",
"title": "Registered Aztec addresses"
},
{
"title": "Deposit address secrets use secp256k1 key exchange",
"url": "https://github.com/aztec-labs-eng/zkmoney-public/blob/f04743f5d57d1b89f9190cad0f6affd28b0793f2/packages/sdk/src/services/sipaStealth.ts#L80-L100"
},
{
"title": "Enclave channel uses P-256 HPKE",
"url": "https://github.com/aztec-labs-eng/zkmoney-public/blob/f04743f5d57d1b89f9190cad0f6affd28b0793f2/vendor/oxide/yarn-project/oxide-lib/src/encryption.ts#L1-L5"
}
],
"id": "futureAdversary",
"value": "Link exposed",
"alsoExposed": [
{
"field": "sender",
"exposure": "exposed"
},
{
"field": "amount",
"exposure": "exposed"
}
]
}
}
},
"anonymitySet": {
"type": "partially-attributed"
},
"attributes": [
{
"id": "zk",
"label": "ZK",
"description": "Uses zero-knowledge proofs to prove private actions without revealing private data."
},
{
"id": "tee",
"label": "TEE",
"description": "Privacy assumptions of this project are secured by trusted hardware."
},
{
"id": "transfers",
"label": "Transfers",
"description": "Private transfers within the shielded pool."
},
{
"id": "anyAmount",
"label": "Any amount",
"description": "Deposits and withdrawals can have any size."
}
],
"category": {
"id": "shieldedLedger",
"label": "Shielded ledger",
"description": "A pool with transfers or DeFi inside. Hides who pays whom and which deposit became which withdrawal."
},
"exitWindow": {
"value": "Infinite",
"sentiment": "good",
"orderHint": 9007199254740991,
"description": "The escrow and the approved enclave image are immutable.",
"walkawayTest": {
"passed": false,
"reason": "Withdrawals and refunds need a live enclave running the approved image on AWS Nitro. The released wallets also depend on zk.money services, so independent operation needs a modified desktop build."
}
},
"relayerTracking": {
"type": "onchainEvents",
"sources": [
{
"address": "eth:0xdf410ad448A0f7165181FBdB32f8896f4a0d9449",
"sinceTimestamp": 1790298635,
"extractor": "zkMoneyWithdrawalRelayer",
"params": {
"tokenAddress": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"executorAddress": "0xC2363b7155EE8391C5395B72C46a6d22BF49151c",
"operationExecutor": "0xe883686d9EC4E0430f2233A6BF12B2D226a39e19"
}
}
]
},
"reproducibility": {
"value": "Partially reproducible",
"sentiment": "warning",
"description": "The contract, desktop wallet, enclave and circuit sources are public. The deployed refund and resolver verifiers match the published circuits. The approved enclave binary remains unreproduced. The resolver service, frozen-chain snapshot service and hosted wallet release source are unpublished. Verification instructions cover the refund and resolver circuits and the Aztec token pinned by the Ethereum portal."
},
"riskSummary": "## Funds can be stolen if\n\n1. Aztec's private execution or refund proof is unsound and the enclave layer also fails.\n2. malicious wallet code obtains a harmful signature, or substituted unsigned contract lists redirect future deposits and payments.\n3. the NameRegistry owner or owner of zk.money in ENS redirects future payments to names.\n\n
\n\n## Funds can be lost if\n\n1. a user loses their passkey.\n2. every AWS-attested enclave stops running.\n3. resolver screening blocks an external payment and the recipient lacks the tooling to re-derive its deposit address.\n\n
\n\n## Privacy can be lost if\n\n1. a user pays a new contact, whose handshake reveals the recipient (see public observer).\n2. the resolver operator links L1 deposits to L2 recipients, or an enclave or AWS Nitro is compromised (see privileged insider).\n3. anyone on the user's network path times their Aztec transactions, since Desktop has no Tor or proxy setting (see network observer).\n4. the portal freezes, and refunds publish note or deposit amounts on Ethereum.\n5. elliptic-curve cryptography is broken, which decrypts data published to Ethereum (see future adversary).",
"tokens": [
{
"token": {
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"iconUrl": "https://assets.coingecko.com/coins/images/9956/large/Badge_Dai.png?1696509996",
"symbol": "DAI",
"decimals": 18,
"priceId": "dai",
"sinceTimestamp": 1790298635
},
"buckets": [
{
"id": "zkmoney-DAI",
"type": "pool",
"label": "DAI",
"address": "eth:0xdf410ad448A0f7165181FBdB32f8896f4a0d9449",
"sinceTimestamp": 1790298635,
"anonymitySet": {
"minimumAmounts": [
"200000000000000000000"
]
},
"deposit": {
"event": "0x8154af7b1b360f500640de68c82af19c52c4ad4189d7a7c7a41506e19a1fdd6c",
"extractor": "zkMoneyDeposit",
"params": {
"tokenAddress": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"fundingCut": "100000000000000000",
"factoryAddress": "0xc357E34D4C7520a83C9Ec0a242Ba52b4ecABa1Fc",
"depositImplementation": "0xF714D8Cf287F4A410b018514074A9371BC45461b",
"registrationImplementation": "0x0934F010d59b552949DBe44AcBE5AFf0e32C8C34",
"fundingTokens": [
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"0xdAC17F958D2ee523a2206206994597C13D831ec7"
],
"exchangeAddress": "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7",
"historyFromBlock": 26051085
}
},
"withdrawal": {
"event": "0x0ef2e2e9f18042ca214d1bee833209f28326ffa8f4a6b0dc92172caf71bc5433",
"extractor": "zkMoneyWithdrawal",
"params": {}
}
}
]
}
],
"trackedOn": [
"ethereum"
],
"upgradesAndGovernance": {
"content": "The core smart contracts of Aztec Network and zk.money are immutable.\n\n### Enclave signers and freeze\n\nAnyone can permanently register an enclave signer with an AWS Nitro attestation up to 1 hour old, and 2 are registered. If Aztec governance changes its canonical rollup, anyone can freeze the portal for good, which stops deposits and enables refunds at the last proven checkpoint.\n\n### Names and services\n\nTwo Aztec Labs EOAs control *.zk.money names. The deployer owns the NameRegistry and can replace its registration, metadata and resolver contracts, which lets it reassign names and redirect future payments. It also owns zk.money in ENS, which the DNS holder can reclaim. The domain owner can refuse claims, sign custom fees and add permanent fee beneficiaries, which users pick from in their registration intent. Aztec Labs also controls the hosted wallet, the desktop releases and the two unsigned contract lists both wallets currently use."
},
"zkCatalogId": "barretenberg"
}