On Monad.
On Monad, Erebus settles through its own EVM shielded pools for WMON and USDC, deployed on Monad testnet. Agents negotiate over an encrypted channel, authorize one canonical agreement, and pay with a proof generated on their own machine.
This page covers the published 0.3.0.dev2026101307 release. The deployment is test-only, single-operator and unaudited. The full operator guide is metropolis-install.md.
Install
uv venv --python 3.11 erebus-metropolis
uv pip install --python erebus-metropolis/bin/python \
--no-config \
--index https://poulavbhowmick03.github.io/erebus-metropolis/simple/ \
--default-index https://pypi.org/simple --index-strategy first-index \
"erebus-mcp-server==0.3.0.dev2026101307"
export PATH="$PWD/erebus-metropolis/bin:$PATH"
printf '%s' '{"method":"version"}' | erebus-negotiateThree packages install from the release index: erebus-cli, erebus-sdk and erebus-mcp-server, with the native commands they wrap. Builds exist for macOS 11+ on Apple silicon and Linux x86-64. Keep the index order: the release index first, PyPI only for missing dependencies. Set UV_HTTP_TIMEOUT=300 if release downloads time out.
Set up a buyer and a seller
Every participant pins the release first, so later commands can check each installed binary and each pool against the signed authorization:
B="$PWD/erebus-metropolis/bin"
"$B/erebus-init" --metropolis pins --version 0.3.0.dev2026101307 --directory ./pinsCOMMON=(--pool wmon --bin "$B" --pins ./pins \
--deployment ./pins/monad-testnet-shielded-v2.json \
--rpc-url https://testnet-rpc.monad.xyz --peer-rpc-url https://rpc.ankr.com/monad_testnet)The seller serves a resource and quotes a price. Each side runs its own install, on its own machine, with its own funded gas address. Gas keys are passed by path only.
"$B/erebus-init" --metropolis init --role seller --directory ./seller \
--endpoint 127.0.0.1:9211 --signer-address <seller gas address> \
--transaction-key-file <seller gas key file> "${COMMON[@]}"
# exchange shares, then:
"$B/erebus-init" --metropolis connect --directory ./seller --peer-share ./buyer/share \
--resource dataset.snapshot.v1 --amount <price> --payload-file <resource file> --port 9213
EREBUS_ACCESS_CONFIG="$PWD/seller/access.json" "$B/erebus-access-service" &"$B/erebus-init" --metropolis init --role buyer --directory ./buyer \
--endpoint 127.0.0.1:9212 --signer-address <buyer gas address> \
--transaction-key-file <buyer gas key file> --maximum-price <max> "${COMMON[@]}"
"$B/erebus-init" --metropolis connect --directory ./buyer --peer-share ./seller/share \
--resource dataset.snapshot.v1 --amount <opening offer>
"$B/erebus-init" --metropolis wallet-policy --directory ./buyer \
--maximum-amount <per-action cap> --allow wrap --allow approve --allow deposit --allow status
"$B/erebus-init" --metropolis doctor --directory ./buyer- pins
- Downloads the release manifest, owner authorization, deployment record and each pool's signed hosting manifest over HTTPS, and checks them against each other.
- init
- Checks every installed command against the release hashes, then creates the participant's negotiation keys and identity binding. Rust creates all keys; the script passes paths only.
- connect
- Exchanges public shares with the counterparty and writes negotiate.json and mcp.json. A seller also gets access.json and an offer.
- wallet-policy
- Opts the buyer agent into wallet writes, one method at a time, under a per-action cap. Without it the agent can only read notes and sync.
- doctor
- Read-only. Checks binary hashes, owner-only files, both RPC endpoints on chain 10143, and the gas signer's balance. Prints no secrets.
The buyer needs testnet MON for gas and for the WMON it wraps. Nothing in setup sends a transaction; each funding call is a real testnet transaction from the buyer’s gas address.
Connect the agents
connect writes an mcp.json for each participant: one erebus-mcp-server entry with paths to its own configuration and keys. Give the buyer agent ./buyer/mcp.json and the seller agent ./seller/mcp.json. Each agent sees only its own server.
- wrap_wallet
- buyer
- Wrap testnet MON into WMON. Bounded by the wallet policy; reuse the same operation_ref on retry.
- approve_wallet
- buyer
- Approve the pool for a bounded amount of this asset only.
- deposit_wallet
- buyer
- Fund one shielded note under a durable reference. Never use a new reference to retry.
- sync_wallet
- buyer
- Confirm pending wallet operations and catch up on pool history. Call it after a deposit.
- wallet_notes · wallet_status
- buyer
- Read-only views of notes and paired account state.
- negotiate_deal
- buyer, seller
- Negotiate and authorize one fixed-policy deal over the encrypted channel. Never submits payment.
- check_settlement_funding
- buyer
- Check that a funded note covers the authorized deal, without signing or submitting.
- settle_deal
- buyer
- Prove locally and submit, with at most one automatic broadcast attempt.
- recover_deal
- buyer
- Observe and reconcile the operation. It cannot sign, prove or submit, so it is always safe to repeat.
- retrieve_service_access
- buyer
- Fetch the paid resource from the seller's access service and verify its hash.
The price and limits come from each operator’s configuration, not from the model. The agent decides when to call each tool.
One deal, end to end
- 01Fund: wrap_wallet → approve_wallet → deposit_wallet → sync_wallet
- 02Agree: both agents call negotiate_deal with the same operation_ref and get the same deal_commitment
- 03Check: check_settlement_funding reports ready
- 04Pay: settle_deal, once
- 05Recover: recover_deal until payment_verified is true, if the reply was pending or lost
- 06Retrieve: retrieve_service_access, then check resource_verified
Every write carries an operation reference. Persist it before the call and reuse it on retry, so a lost reply never becomes a second payment. A pending settle_deal reply is normal: recover_deal observes the chain until the payment is final.
Disclose one deal
An auditor gets its own directory and key. The seller exports a grant scoped to one deal, and the auditor verifies the agreement and the payment with erebus-shielded-disclosure. A grant from the wrong issuer is refused. Payment verification does not prove delivery.
"$B/erebus-init" --metropolis auditor --pool wmon --directory ./auditor \
--bin "$B" --pins ./pins --deployment ./pins/monad-testnet-shielded-v2.json \
--rpc-url https://testnet-rpc.monad.xyz --peer-rpc-url https://rpc.ankr.com/monad_testnetWho sees what
- Public chain reader
- Sees: Pool contract, gas sender, commitments, nullifiers, roots, timing, transaction shape
- Hidden: Negotiation, private payment amount and recipient
- Deposit and withdrawal observer
- Sees: Public token transfers, amounts, accounts, timing
- Hidden: A direct mapping to later private notes
- Counterparty
- Sees: Its own negotiation and agreed terms
- Hidden: Other deals and spending secrets
- Auditor with one grant
- Sees: The selected deal and its payment evidence
- Hidden: Other deals and spending authority
- Public-bound mode (V1)
- Sees: Accepted terms, amount, recipient, asset and timing are public
- Hidden: Earlier encrypted negotiation and rejected offers
From the Monad threat model. These are design targets for the shielded rail, not an audited guarantee.
Limits and evidence
- Test-only, single-operator deployment on Monad testnet. Unaudited, with no independent acceptance yet.
- Funding, withdrawals and the outer gas sender are public, and a small anonymity set allows amount and timing inference.
- A fresh wallet must index pool history before its first private operation; on public RPC endpoints this currently takes hours.
- Payment verification is not proof of delivery. There is no escrow or conditional release.
- WMON pool
- 0x8868f35140f3602c80e2c76132740b6f0c0b409d
- USDC pool
- 0x863f540471c0ad33c68d1218f31e8c9fe9cd50fb
- Shielded WMON payment (2026-10-11)
- 0xe01666d8c4e16efe8195da8047674c71a325ee20ff250f02f4fdf570a04934fa
- x402 access payment (2026-10-04)
- 0x8a0272e69188ac3be52783ddfc4d4436496a58f2d5c63d808cd3320a1fa5df43
Current state and every qualification run: metropolis-status.md.