Deploying the contracts

On the local development network npm run deploy writes deployments.json and you never think about it. When the chain is yours, you put AIOUM's contracts and services on it: the deploy, the TLS edge, the facilitator, the indexer, the agent wallets and the verification gate, in the order you run them. The repo ships the configuration (an env-driven deploy, a hardened facilitator, TLS at the edge, a self-host indexer stack, a budget-capped agent wallet); you bring a funded key, a domain and the chain. Deploying your own network is the full playbook with an owner on every line; Operating the network is running it afterwards.

1. Deploy the contracts to your chain

offchain/src/deploy.ts is env-driven. With no env set it targets the local development network (Anvil, mock tokens, demo funding). Set any of DEPLOYER_PRIVATE_KEY / USDC_ADDRESS (or REAL_CHAIN=1) and it switches to live-chain mode: no mock tokens, no minting, and a post-deploy verification checklist. See offchain/.env.example.

cd offchain
RPC_URL=https://mainnet.base.org \
CHAIN_ID=8453 \
DEPLOYER_PRIVATE_KEY=0x...                                   # a funded EOA \
USDC_ADDRESS=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \    # native USDC on Base \
PERMIT2_ADDRESS=0x000000000022D473030F116dDEE9F6B43aC78BA3 \ # canonical, same on every chain \
ZAI_ADDRESS=0x...                                            # the real ZAI token \
npm run deploy

On exit it runs the verification gate: a non-canonical Permit2 or a mock token still in use blocks the deploy; governance still owned by the deployer prints as a [verify] warning listing what the handover will change. The handover is yours: npm run handover with DAO_OWNER=0x<timelock> and CONFIRM_HANDOVER=1 sets the arbitrator to the DAO and transfers the staking, reputation, payment, dispute and validation contracts to the TimelockController, so the deployer key holds no privileged role (Operating the network for key handling). Then publish deployments.json: every node, facilitator and agent on your network starts from it.

2. TLS for the nodes

The Node.js services speak plain HTTP and, apart from the private node and the monitor, listen on every interface. Keep the OS firewall closed to their ports and terminate TLS at the edge with deploy/Caddyfile, which gets automatic Let's Encrypt certs:

caddy run --config deploy/Caddyfile      # after pointing your domains' DNS at the host

Expose the private node only over TLS: it is bearer-token gated, but the token and the tool I/O need encryption in transit. Bind it with PRIVATE_NODE_HOST=0.0.0.0, keep the firewall closed to :8770, and let Caddy be the only thing that reaches it.

3. Harden + run the facilitator

The facilitator (offchain/src/facilitator/server.ts) holds only a gas key, so it is non-custodial, and it is hardened: strict EIP-3009 input validation, an asset allowlist, a per-request amount ceiling, per-IP rate limiting, an in-flight cap, EIP-3009 nonce replay rejection, sanitized errors. All knobs default permissive for the local development network; for a public instance set them in .env:

FACILITATOR_API_KEY=$(openssl rand -hex 32)   # require Authorization: Bearer <key>
FACILITATOR_MAX_AMOUNT=1000000000             # 1000 USDC ceiling, in base units
FACILITATOR_RATE_MAX=30                        # per IP per minute

Non-custodial means anyone can run one: no single-relayer chokepoint. Run several behind the Caddyfile and let clients fall back to direct openSession*.

4. Indexing: self-host the subgraph

Two indexes serve your network. The live directory an agent searches for tools is the discovery indexer from Every setting, which rescans the chain and probes nodes by itself. History at scale, for explorers and dashboards, is the subgraph: subgraph/docker-compose.yml is a complete graph-node + IPFS + Postgres stack (Operating the network for monitoring and indexing). Fill subgraph/networks.json with the addresses and start block from step 1, then:

cd subgraph
docker compose up -d
npm run codegen && npm run build
npm run create-local && npm run deploy-local   # query at http://localhost:8000/subgraphs/name/aioum/aioum-v2

The subgraph feeds your explorer, dashboards and analytics. The app's NEXT_PUBLIC_INDEXER_URL stays pointed at the discovery indexer. The Graph's decentralized network is the alternative to self-hosting: same graph deploy, different --node.

5. Agent wallets / session keys (the "set a budget once" UX)

This is the experience AIOUM is about: set a budget once, then let the agent pay per call with no human in the loop. The private node's scheduler already runs that way under a budget-capped agent wallet: a dedicated signer (account index AGENT_ACCOUNT_INDEX) signs every receipt and the executor refuses to spend past the job's per-run budget. ERC-4337 session keys are the same model: a scoped key that pays per call up to a cap.

On-chain, the ERC-4337 smart account (src/aa/AIOUMAccount.sol) enforces the cap with session keys (scope: the account's openSessionFor; limit: total spend cap; expiry), backed by a gas-sponsoring paymaster and a bundler relay (account-abstraction guide). The app's Wallet budget page is its front-end: connect a wallet, deploy the smart account, fund it, authorize a key, hand the key to the agent. The receipt-signing seam (signVoucher in offchain/src/sdk/voucher.ts) is the same in both cases; only who holds the key and how the cap is enforced changes.

6. Verify before funding

Run npm run verify-deploy against the published deployments.json. It fails unless every governance contract's owner() is the Timelock, DisputeManager.arbitrator() is the Timelock, treasury() on the payment and dispute contracts matches the recorded treasury, Permit2 is the canonical singleton, USDC and ZAI are the real tokens (no public mint), the EntryPoint is canonical, and no accept-everything paymaster is funded. Fund the paymaster and the treasury once it passes. The go-live checklist lists every step with its owner.

You run it all yourself: the local development network, a selling node and its adapters, a private node, every setting, and the contracts on a chain of your own. Now build on it, from the buying side: Claude connected to the marketplace as a paying agent.

Next: Connect Claude via MCP — how a node's MCP server gates every tool call behind an x402 payment, and what Claude sends to get through it.