blackpool
# Blackpool
> Private payments that leave no trail.
[](https://github.com/blackpooldev/blackpool/actions/workflows/build.yml)
[](https://www.npmjs.com/package/@blackpool/cli)
[](LICENSE)
[](#networks)
[](https://sourcify.dev)
[](https://blackpool.cash/app)
[](#mcp-server)
Shield an asset once. Send, swap and bridge it privately after that, from a web app, a CLI or an MCP server for AI agents, with no account, no custody and no trail back to your wallet.
Blackpool is a set of zero-knowledge privacy pools on EVM chains. Every pool is a Poseidon Merkle tree of encrypted notes; spending a note means proving in zero knowledge (Groth16) that you own a leaf without saying which one. A relayer submits the transaction and pays the gas, so your wallet never appears on-chain again after the deposit.
```
wallet ──sign once──► account keys (derived from the signature)
│
▼
┌────────────── private balance (notes in a pool) ──────────────┐
│ │ │ │
private send same-chain swap private bridge recover
(any EVM address) (ETH ⇄ stablecoin via DEX) (NEAR Intents) (from signature)
│ │ │
└──────────── relayer submits, pays gas ──────────┘
```
The relayer sees a proof and an encrypted payload. It cannot link a withdrawal to a deposit, cannot spend notes and cannot decrypt anything: the AES key for recovery data is `keccak256(signature)` and the backend only ever learns a one-way derived identifier.
## Networks
| Chain | Pools | Status |
|---|---|---|
| Robinhood Chain (4663) | ETH · USDG | **live** |
| Base (8453) | ETH · USDC | **live** |
| Arbitrum One (42161) | ETH · USDC | **live** |
| BNB Smart Chain (56) | BNB · USDC · USDT | **live** |
Pool proxies (UUPS; the admin can upgrade and pause, nothing else). Admin on every chain: the 2-of-3 Safe `0x401027251176A8AFec701fE37412edeC45ec6FdB`:
| Chain | ETH / BNB pool | Stablecoin pool(s) |
|---|---|---|
| Robinhood Chain | [`0x993490DCc199A41D5A2A412e30bA205FD43B9D69`](https://robin.etherscan.io/address/0x993490DCc199A41D5A2A412e30bA205FD43B9D69) | USDG [`0xeBfC2287Efc2FEDc51e24124A582bcb6CcDD5300`](https://robin.etherscan.io/address/0xeBfC2287Efc2FEDc51e24124A582bcb6CcDD5300) |
| Base | [`0xEC0FB87E77Fb18Abbbda726E69adFc561b148A02`](https://basescan.org/address/0xEC0FB87E77Fb18Abbbda726E69adFc561b148A02) | USDC [`0x71716bCc48Ec226De36fa07d11959b1C27e9EC19`](https://basescan.org/address/0x71716bCc48Ec226De36fa07d11959b1C27e9EC19) |
| Arbitrum One | [`0xEC0FB87E77Fb18Abbbda726E69adFc561b148A02`](https://arbiscan.io/address/0xEC0FB87E77Fb18Abbbda726E69adFc561b148A02) | USDC [`0x59E4f3A645cD9d23c99e12a00e541B77331B8Ad4`](https://arbiscan.io/address/0x59E4f3A645cD9d23c99e12a00e541B77331B8Ad4) |
| BNB Smart Chain | [`0xEC0FB87E77Fb18Abbbda726E69adFc561b148A02`](https://bscscan.com/address/0xEC0FB87E77Fb18Abbbda726E69adFc561b148A02) | USDC [`0x59E4f3A645cD9d23c99e12a00e541B77331B8Ad4`](https://bscscan.com/address/0x59E4f3A645cD9d23c99e12a00e541B77331B8Ad4) · USDT [`0x3A3225C54b6D326C855eEa77d76a6F143Df6555D`](https://bscscan.com/address/0x3A3225C54b6D326C855eEa77d76a6F143Df6555D) |
Admin on every chain: `0xB1aCad20c0D0F6dA98841b09369eFAe46FdD8126`. Several addresses repeat across chains (same deployer, same nonce) while being different contracts: always read an address with its chain.
Implementations, verifiers, hashers and deploy blocks for every chain are in [`deploy/ADDRESSES.md`](deploy/ADDRESSES.md). The running API reports the pools it serves at `GET https://api.blackpool.cash/api/health`.
## Using it
**Web app.** [blackpool.cash/app](https://blackpool.cash/app): connect a wallet, sign once, shield. [blackpool.cash/recover](https://blackpool.cash/recover) recovers anything that got stuck mid-flow from the same signature, on any device.
**CLI.** [`@blackpool/cli`](https://www.npmjs.com/package/@blackpool/cli) drives the same API from a terminal, for scripts and agents:
```
npm i -g @blackpool/cli # or: npx @blackpool/cli help
blackpool login # key via hidden prompt (or BLACKPOOL_KEY for agents/CI)
blackpool balance --chain robinhood
blackpool deposit 0.5 --chain robinhood # shield
blackpool send 0x… 0.1 --chain robinhood # private send, no gas from you
blackpool send 0x… max --chain all # send every private balance to one address
blackpool bridge sol_usdc <solana address> 0.1 --from hood_eth
blackpool recover --chain all # sweep anything stranded, idempotent
```
The CLI keeps the key you give it and the cached sign-in signature in `~/.blackpool/` (mode 600). `BLACKPOOL_KEY` skips the interactive login for agents and CI.
## MCP server
Blackpool ships a [Model Context Protocol](https://modelcontextprotocol.io) server, so AI agents in any MCP client (Cursor, VS Code, desktop chat apps and more) can shield, send, swap and bridge privately as tool calls. It is listed in the official MCP Registry as [`cash.blackpool/blackpool`](https://registry.modelcontextprotocol.io/v0.1/servers/cash.blackpool%2Fblackpool/versions/latest).
**Local server (stdio)**, implemented in [`cli/bin/mcp.js`](cli/bin/mcp.js). Proofs are built on the machine that runs it and the key never leaves it:
```json
{
"mcpServers": {
"blackpool": {
"command": "npx",
"args": ["-y", "@blackpool/cli@latest", "mcp"],
"env": { "BLACKPOOL_KEY": "0x..." }
}
}
}
```
| Tool | What it does | |
|---|---|---|
| `blackpool_address` | Address of the agent wallet | read-only |
| `blackpool_balance` | Private and public balances, per pool or every chain | read-only |
| `blackpool_deposit` | Shield funds from the agent wallet into a private pool | writes |
| `blackpool_send` | Pay any EVM address privately (`max` sends the whole balance) | writes |
| `blackpool_swap` | Private same-chain swap between the native coin and the stablecoin | writes |
| `blackpool_bridge` | Private cross-chain transfer via NEAR Intents | writes |
| `blackpool_bridges` | Every bridge of this account with its status | read-only |
| `blackpool_assets` | Bridge destinations and valid origins | read-only |
| `blackpool_recover` | Sweep anything stranded on one-time burners back into the private balance | idempotent |
`BLACKPOOL_MCP_TOOLS=balance,send` limits the tools, `BLACKPOOL_MCP_READONLY=1` exposes only the read-only ones. The server starts and answers `initialize` and `tools/list` without a key; tools that move funds need `BLACKPOOL_KEY`.
**Hosted server (Streamable HTTP)**, read-only, no key: `https://mcp.blackpool.cash/mcp`, with `blackpool_assets`, `blackpool_bridge_quote`, `blackpool_fees`, `blackpool_analytics`, `blackpool_status` and `blackpool_guide`.
Full agent guide: [AGENTS.md](AGENTS.md).
## How it works
- **Sign-in.** The wallet signs one fixed message. `keccak256(sig)` becomes the encryption key, its hash the UTXO spending key; the same wallet reproduces the same account anywhere. Keys, note scanning and Groth16 proofs are computed on the user's device (web worker in the app, Node in the CLI, `cli/lib/zk.js`); the relayer API receives finished proofs only and never the signature.
- **Shield.** A deposit inserts a commitment `Poseidon(amount, pubkey, blinding)` into the pool's tree. The amount is free-form: no fixed denominations.
- **Spend.** A 2-in / 2-out Groth16 circuit (`circuits/`) proves ownership of the inputs, correctness of the outputs and that the nullifiers are fresh. The relayer verifies the proof on-chain through `Verifier2`.
- **Swap.** Same-chain swaps withdraw to a one-time burner wallet, swap on the chain's DEX, and re-shield. Burner keys are registered encrypted (client-side AES-GCM) so a stalled swap is recoverable from any device.
- **Bridge.** Cross-chain transfers withdraw privately to a NEAR Intents (1Click) solver deposit address; the solver delivers on the destination chain. Refunds go back to the burner, which recovery re-shields.
The protocol reference lives at [blackpool.cash/docs](https://blackpool.cash/docs); the roadmap in [`ROADMAP.md`](ROADMAP.md).
## Repository
```
circuits/ circom circuit (transaction2) + build artifacts
contracts/ EtherPool / ERCPool, MerkleTreeWithHistory, Verifier2, per-chain variants
src/ keypair, UTXO, proving, encryption, registry-auth derivation
scripts/ deploy + upgrade scripts, hasher/verifier generation
cli/ @blackpool/cli
frontend/ Next.js static app (blackpool.cash)
deploy/ the address book (ADDRESSES.md)
test/ hardhat test-suite (149 tests)
```
## Development
```bash
npm ci && npm ci --prefix cli
npm run compile # Hardhat 3 build + Poseidon hasher bytecode
npm run validate:upgrades # OpenZeppelin upgrade-safety checks on every pool contract
npm test # 150 tests, ~2 min (proves real Groth16 proofs)
node scripts/zkParity.js # client-side prover (cli/lib/zk.js) against the reference implementation
```
Contracts build with Hardhat 3 (`hardhat.config.ts`, solc 0.8.24, optimizer 200, EVM `paris`); the runtime bytecode is identical to the deployed implementations. Deploy a pool with `scripts/deployPool.mjs` and prepare an upgrade with `scripts/prepareUpgrade.mjs` (both `npx hardhat run --network <chain> …`, `DEPLOYER_KEY` in the environment). Pools are administered by a Safe: an upgrade deploys the new implementation and writes a Safe Transaction Builder file under `deploy/safe/` with the `upgradeToAndCall`, which the Safe owners sign.
The relayer API and indexer are operated by Blackpool and are not part of this repository; the frontend and CLI talk to `https://api.blackpool.cash`. The frontend is a static export: `cd frontend && npm run build`.
## Security
Non-custodial by construction: no server ever holds a key that can spend a note or decrypt recovery data. The relayer refuses anything that is not a fee-paying withdraw with a known root and unspent nullifiers, and simulates every transaction before broadcasting it.
Found something? Please read [`SECURITY.md`](SECURITY.md) and write to [hello@blackpool.cash](mailto:hello@blackpool.cash) rather than opening a public issue.
## Contributing
Issues and pull requests are welcome; see [`CONTRIBUTING.md`](CONTRIBUTING.md). The cryptographic core (circuit, tree, note format, sign-in message) is frozen — changes there need a migration plan, not a PR.
## License
MIT. See [LICENSE](LICENSE).
TDQS
Scored across 9 tools
Most tools map to clearly distinct actions (deposit vs send vs swap vs recover), but blackpool_bridge (initiate a cross-chain transfer) and blackpool_bridges (list existing bridges) differ only by a plural 's', which is an easy misselection trap. blackpool_assets and blackpool_bridges are also both read-only metadata/list tools that could be confused at a glance. The descriptions do disambiguate once read, which keeps this above a 2.
All nine tools share the same blackpool_ prefix and a flat lowercase style with no camelCase or multi-word mixing, so the surface looks uniform. However, the naming is noun-based for some tools (address, balance, assets, bridges) and verb-based for others (send, deposit, swap, recover), and the singular/plural bridge pair is not a predictable pattern.
Nine tools is well within the sweet spot and each one covers a distinct facet of a private wallet: identity, balances, shield, send, swap, bridge (create/list/assets), and recovery. Nothing appears redundant or padded, and nothing essential is obviously missing from the count.
The lifecycle is largely covered: funding address, shielded balance reads, deposit in, private send out, swap, cross-chain bridge with status listing and destination metadata, plus a recovery sweep for stuck funds. The main gap is an explicit unshield/withdraw-to-public operation and any transaction history beyond bridge records, though send-to-self could work around the former.