{
"redWarning": {
"text": "The vault owner can block withdrawals until deposits expire and become sweepable to the treasury. The proofs rely on a single-party trusted setup.",
"detailAnchor": "permissions"
},
"unverifiedContracts": []
}
display+16-0
{
"badges": [],
"description": "Anonymous access to AI models, prepaid with ETH, that hides which deposit pays for which request.",
"detailedDescription": "zkAPI lets the user prepay AI usage with ETH and chat without revealing which deposit pays for which request. Deposits and withdrawals are public, and the model provider can read the user's prompts.\n\nUsers trust Open Anonymity, which runs the service and owns the vault, and the inference providers behind OpenRouter. The operator approves withdrawals and sees each request's time and budget. The owner can pause the vault, and expired deposits fall to its treasury. The user can leave without the operator through a 1 day escape, as long as their note has not expired.\n\n### Architecture\n\nOpen Anonymity verifies request proofs before issuing API keys. Its signing keys are fixed in the vault. A new key requires proof that the user's balance covers a budget of at least 0.00005 ETH.\n\nThe user's app keeps the exact balance locally. The operator receives a commitment to the user's deposit. Initially, the balance equals the deposit.\n\nThe commitment is homomorphic: the operator can subtract a known charge without reading the balance. It signs the updated commitment. The local app checks the subtraction and signature, then stores the updated state.\n\nThe operator also runs the indexer and a challenger that disputes escapes from outdated balances.\n\n### Flow\n\n1. **Deposit** ETH from your wallet. The vault records its amount and an expiry about 1 month later.\n2. **Request access.** The app proves an active note covers your chosen budget. The operator returns a short-lived OpenRouter key.\n3. **Chat.** Send prompts to OpenRouter with that key.\n4. **Settle.** The operator bills the key's usage.\n5. **Withdraw.** A cooperative close needs the operator's clearance. The vault publishes the note id and remaining balance. It returns the remainder to your chosen address and pays usage to the treasury.\n\n### Keys\n\nLosing the note secret and latest signed balance that are saved by the app loses the funds.\n\n### App\n\nThe ratings assume OA Chat, a hosted browser app with public source and local build instructions. It fetches the whole note tree and proves in the browser. It relays inference through a proxy at refraction.network by default, with a fallback to direct connections. The hosted build runs code beyond the public main branch, including analytics. zkapi-clientd is a local daemon with an OpenAI-compatible API. It asks the operator's indexer for the user's note path and reuses keys across requests, both of which can harm privacy.\n\n### Providers and verifier\n\nOpenRouter and the model provider can read prompts and responses and link requests under one key. Open Anonymity holds the OpenRouter accounts. A verifier running in an attestable Azure confidential container checks that OA's account has provider logging disabled. Its build reproduces from source and matches the attested measurement, see the verification steps. Both clients pin only the verifier's address, so the check only holds when the user verifies it personally.\n\n### Exits\n\n**Escape.** Without a cooperative close, the user starts an escape with their latest signed balance and finalizes it after 1 day. The operator can cancel it with a request proof for that balance, which publishes that request's link. While the owner pauses the vault, no one can start an escape, but one already started still finalizes.\n\n### Compliance\n\nThe vault has no onchain screening. The operator can refuse keys or clearance.\n\n### Fees\n\nUsage is billed in USD and converted to ETH through a Chainlink feed, with no fee on top of the provider's price. The unused balance returns at withdrawal.",
"links": {
"websites": [
"https://chat.openanonymity.ai"
],
"documentation": [
"https://zkapi.openanonymity.ai"
],
"repositories": [
"https://github.com/ethereum/zkapi"
]
}
}
{
"creator": "Open Anonymity",
"projectsForTvs": [
{
"projectId": "zkapi",
"sinceTimestamp": 1790783879
}
],
"proofSystemInfo": "Application-specific request and withdrawal Groth16 circuits over BN254. Poseidon Merkle membership and note-bound Baby-JubJub balance commitments hide the note and balance during authorization. Withdrawals expose the note id and remaining balance.",
"techStack": {
"snark": [
{
"id": "Arkworks",
"type": "Groth16",
"name": "Arkworks",
"description": "Arkworks implementation of Groth16 written in Rust."
},
{
"id": "BN254",
"type": "curve",
"name": "BN254",
"description": "BN254, aka BN256, aka alt_bn128 pairing-friendly 254-bit prime field Weierstrass elliptic curve."
}
]
},
"trustedSetups": [
{
"id": "ZkApiNoteBoundV1",
"name": "zkapi-v2-note-bound-v1 single-party setup",
"proofSystem": {
"id": "Arkworks",
"type": "Groth16",
"name": "Arkworks",
"description": "Arkworks implementation of Groth16 written in Rust."
},
"participantCount": 1,
"risk": "red",
"shortDescription": "The published request and withdrawal keys were generated by one party. Retained setup secrets can allow forged proofs.",
"longDescription": "The request and withdrawal Groth16 keys were generated by one party. There was no multi-party ceremony. Security requires that this party erased the setup secrets, otherwise it can forge withdrawal proofs. Matching public artifacts cannot prove erasure. [Setup implementation](https://github.com/ethereum/zkapi/blob/045b444ea1b52538d1b40273c7cb6ed09468a052/protocol/rust/crates/zkapi-proof/src/compact.rs#L288-L383), [provenance](https://github.com/ethereum/zkapi/blob/045b444ea1b52538d1b40273c7cb6ed09468a052/protocol/setup/v2/README.md)."
}
],
"verifierHashes": [
{
"name": "zkapi note-bound request and withdrawal verifier",
"hash": "0xd31acf861825869e6a84b6b0025cb6940077f5981a10e73d2e4e8e5d7417c853",
"sourceLink": "https://github.com/ethereum/zkapi/blob/045b444ea1b52538d1b40273c7cb6ed09468a052/protocol/rust/crates/zkapi-proof/src/groth16.rs",
"proofSystem": {
"id": "Arkworks",
"type": "Groth16",
"name": "Arkworks",
"description": "Arkworks implementation of Groth16 written in Rust."
},
"knownDeployments": [
{
"address": "eth:0x8e92013Dd7cc86f75b539DBD3814B2e603e0F9C1"
}
],
"verificationStatus": "notVerified",
"verificationSteps": "### Contracts and proof artifacts\n\nReviewed [ethereum/zkapi revision](https://github.com/ethereum/zkapi/tree/045b444ea1b52538d1b40273c7cb6ed09468a052), whose vault, adapter and circuits match the deployment revision reported by the production manifest. Compile with the checked-in configuration: solc 0.8.28, optimizer 200, viaIR and Prague.\n\n```bash\ngit clone https://github.com/ethereum/zkapi.git\ncd zkapi\ngit checkout 045b444ea1b52538d1b40273c7cb6ed09468a052\ncd demo/contracts\nforge build --skip test --build-info\ncast tx 0xf753fd93c7e672f7b851f261f600e06930e502bdfd73be29ce8a065643df6985 --json --rpc-url \"$ZKAPI_RESEARCH_RPC_URL\" > vault-tx.json\ncast tx 0x45f2f5259476afd5f64a6a62a36c9012c3a26efcdd35b048a7fac5ae1ba43780 --json --rpc-url \"$ZKAPI_RESEARCH_RPC_URL\" > verifier-tx.json\n```\n\nThe adapter creation bytecode matches exactly, including metadata. The vault matches after linking the discovered Poseidon address. Decode its ten constructor arguments from the remaining transaction input. Sources are verified on Etherscan: [vault](https://etherscan.io/address/0x4386FDbdA35D995beB3BF8625118Ec5982ec81fe#code), [adapter](https://etherscan.io/address/0x8e92013Dd7cc86f75b539DBD3814B2e603e0F9C1#code), [Poseidon](https://etherscan.io/address/0xc6B55e86668d8c446B3D81273AAb9CBb20F28c7f#code).\n\nThe deployed verification-key coordinates and public inputs match the [published setup artifacts](https://github.com/ethereum/zkapi/tree/045b444ea1b52538d1b40273c7cb6ed09468a052/protocol/setup/v2), and the proving-key hashes match the SDK and production pins. A single-party setup with fresh randomness yields different keys each time, so matching artifacts show that the deployed keys are the published ones. Only the setup party knows whether its secrets were erased.\n\n### Frontend and local client\n\nThe [browser frontend](https://github.com/OpenAnonymity/oa-chat/blob/60ed5be2957d984c70a7299474927becec47b61f/README.md#quick-start) and the [local API daemon](https://github.com/ethereum/zkapi/blob/045b444ea1b52538d1b40273c7cb6ed09468a052/zkapi-clientd/README.md) have public source and build instructions. Both still depend on the operator's authorization and inference services.\n\n### Verifier enclave\n\nThe mainnet verifier is `verifier-production-20260917.openanonymity.ai`, pinned in the hosted app's [browser config](https://chat.openanonymity.ai/zkapi/browser-config.json). It runs in an Azure confidential container on AMD SEV-SNP and serves a hardware attestation. Its source, [OpenAnonymity/oa-verifier](https://github.com/OpenAnonymity/oa-verifier), is pinned to commit `4299cfa` by the [production rollout](https://github.com/OpenAnonymity/oa-verifier/blob/86b7031c2f15d01d19efb77f547812e29992d4d9/deploy/production/rollout.py#L27-L29).\n\n```bash\ncurl -sS \"https://verifier-production-20260917.openanonymity.ai/attestation?nonce=$(date +%s)\" > attestation.json\n# 1. the JWT in .token is signed by Azure Attestation (.verify_at), its x-ms-sevsnpvm-hostdata equals sha256 of the decoded .policy\n# 2. the policy lists one dm-verity layer hash for the verifier container\ngit clone https://github.com/OpenAnonymity/oa-verifier && cd oa-verifier\ngit checkout 4299cfa136c90550737dd46c89dba586c213159b\nnix build .#container && docker load < result\n# 3. push oa-verifier:latest to a local registry, then\ngo install github.com/Microsoft/hcsshim/cmd/[email protected]\ndmverity-vhd roothash -i localhost:5000/oa-verifier:latest\n```\n\nThe rebuilt image matches the published `ghcr.io/openanonymity/oa-verifier@sha256:60f9892b…` in nix store path, config and layer, and its layer root hash equals the attested policy. Pushing through a different docker version changes the compressed manifest digest, while the measured layer hash stays. The attestation also binds the TLS key of the live endpoint. Both clients pin only the verifier's address, so repeat the check when it matters."
}
]
}
interopConfig+1-0
null
privacyInfo+347-0
{
"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.",
"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.",
"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."
},
"asset": "exposed",
"linkage": {
"verdict": "atRisk",
"note": "Depends on what the operator retains."
}
},
"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",
"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).",
"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."
}
}
{
"ethereum": {
"roles": [],
"actors": [
{
"id": "EOA-1",
"name": "EOA 1",
"accounts": [
{
"address": "eth:0x83f7eA47811A288f2052Bc31aaAE0803c761D156",
"type": "EOA",
"isVerified": true,
"name": "0x83f7…D156",
"url": "https://etherscan.io/address/0x83f7eA47811A288f2052Bc31aaAE0803c761D156",
"displayName": "EOA 1"
}
],
"chain": "ethereum",
"description": "* Can interact with ZkApiVault\n * pause and unpause deposits, cooperative withdrawals and new escape withdrawals, and change the treasury receiving consumed balances and expired notes. Pausing can prevent users from exiting before their notes become sweepable ",
"discoveryDrivenData": true
}
]
}
}
contracts+55-0
{
"addresses": {
"ethereum": [
{
"name": "ZkApiVault",
"isVerified": true,
"address": "eth:0x4386FDbdA35D995beB3BF8625118Ec5982ec81fe",
"upgradeability": {
"proxyType": "immutable",
"admins": [],
"implementations": [],
"immutable": true
},
"chain": "ethereum",
"description": "Escrows ETH for anonymous API authorizations as publicly numbered notes. A Groth16 proof closes a note with operator clearance, or starts a delayed escape that any request proof with the same nullifier cancels. Closing reveals the note id, payout address and remaining balance and sends the used part to the treasury. Anyone can sweep an expired note entirely to the treasury, also while paused.\n* Roles:\n * **owner**: EOA 1",
"discoveryDrivenData": true,
"url": "https://etherscan.io/address/0x4386FDbdA35D995beB3BF8625118Ec5982ec81fe#code"
},
{
"name": "Groth16ProofAdapter",
"isVerified": true,
"address": "eth:0x8e92013Dd7cc86f75b539DBD3814B2e603e0F9C1",
"upgradeability": {
"proxyType": "immutable",
"admins": [],
"implementations": [],
"immutable": true
},
"chain": "ethereum",
"description": "BN254 Groth16 verifier containing the request and withdrawal verification keys for zkapi-v2-note-bound-v1. Request proofs hide the note identity, exact balance and state signature. Withdrawal proofs expose the note id, destination, final balance and nullifier. The published circuit-specific keys were generated in a single-party setup. Retained setup secrets can allow forged proofs.\n",
"discoveryDrivenData": true,
"url": "https://etherscan.io/address/0x8e92013Dd7cc86f75b539DBD3814B2e603e0F9C1#code"
},
{
"name": "Bn254Poseidon",
"isVerified": true,
"address": "eth:0xc6B55e86668d8c446B3D81273AAb9CBb20F28c7f",
"upgradeability": {
"proxyType": "immutable",
"admins": [],
"implementations": [],
"immutable": true
},
"chain": "ethereum",
"description": "Linked Poseidon hash library used by the vault for active-note leaves and Merkle updates. Its BN254 parameters must agree with the request and withdrawal circuits.\n",
"discoveryDrivenData": true,
"url": "https://etherscan.io/address/0xc6B55e86668d8c446B3D81273AAb9CBb20F28c7f#code"
}
]
},
"risks": [],
"zkVerifiers": [
"eth:0x8e92013Dd7cc86f75b539DBD3814B2e603e0F9C1"
]
}
[
{
"id": "193c1624",
"date": "Wed, 07 Oct 2026 11:42:45 GMT",
"timestamp": 1791373302,
"description": "Initial discovery of the active native ETH vault, its Groth16 proof adapter and linked Poseidon library. All three contracts were verified from public source. The owner can pause new exits and change the treasury.",
"isHighSeverity": false,
"changeCount": 3,
"sections": [
{
"kind": "initial-discovery",
"body": "```diff\n+ Status: CREATED\n contract ZkApiVault (eth:0x4386FDbdA35D995beB3BF8625118Ec5982ec81fe) [zkapi/ZkApiVault]\n +++ description: Escrows ETH for anonymous API authorizations as publicly numbered notes. A Groth16 proof closes a note with operator clearance, or starts a delayed escape that any request proof with the same nullifier cancels. Closing reveals the note id, payout address and remaining balance and sends the used part to the treasury. Anyone can sweep an expired note entirely to the treasury, also while paused.\n```\n\n```diff\n+ Status: CREATED\n contract Groth16ProofAdapter (eth:0x8e92013Dd7cc86f75b539DBD3814B2e603e0F9C1) [zkapi/Groth16ProofAdapter]\n +++ description: BN254 Groth16 verifier containing the request and withdrawal verification keys for zkapi-v2-note-bound-v1. Request proofs hide the note identity, exact balance and state signature. Withdrawal proofs expose the note id, destination, final balance and nullifier. The published circuit-specific keys were generated in a single-party setup. Retained setup secrets can allow forged proofs.\n```\n\n```diff\n+ Status: CREATED\n contract Bn254Poseidon (eth:0xc6B55e86668d8c446B3D81273AAb9CBb20F28c7f) [zkapi/Bn254Poseidon]\n +++ description: Linked Poseidon hash library used by the vault for active-note leaves and Merkle updates. Its BN254 parameters must agree with the request and withdrawal circuits.\n```"
}
]
}
]