The agent layer for peer DeFi: AI counterparties negotiate trades P2P, settle atomically on EVM
Parley is a peer-to-peer DeFi negotiation layer where two AI agents do the work the user doesn't want to: discover counterparties, exchange quotes, and settle atomically on Ethereum.
The user types "swap 50 USDC for ETH" into a Telegram bot. Their User Agent (an LLM with custom tools) broadcasts a signed intent over an encrypted P2P mesh — no central broker, no orderbook, no presence service. Market Maker Agents running independently across the network price the intent deterministically (Uniswap TWAP + spread) and reply with EIP-712-signed offers. The User Agent ranks them, shows a side-by-side card with each MM's reputation and "vs Uniswap" delta, and the user picks one with a single tap.
Settlement is a two-sided lock: both parties deposit into a single Solidity contract, then settle() swaps atomically — neither side can rug. The user's wallet is the only place a private key signs anything; the User Agent has no spendable funds and submits no transactions. If a peer offer doesn't beat Uniswap, the agent surfaces a direct on-chain Uniswap v3 swap as a fallback in the same Mini App.
Identity is on-chain ENS subnames (mm-1.parley.eth, mm-2.parley.eth are live on Sepolia). Reputation is computed, not stored — every trade writes a verifiable TradeRecord blob to 0G Storage with a Merkle proof, and any client can score an MM or user by replaying that history. A misbehaving counterparty leaves a contradicting record on the other side, visible to anyone who looks.
Live on Sepolia: 4-container stack, make deploy-local, two MMs competing on every quote.
Stack. pnpm monorepo with five packages: a Foundry contract (Settlement.sol), a Hermes Agent runtime (Nous Research) wired into Telegram, a deterministic TypeScript MM daemon with no LLM in the pricing path (auditable spot+spread), a Next.js + wagmi + WalletConnect Mini App, and shared TypeScript types.
Transport: Gensyn AXL. Encrypted Yggdrasil mesh with a polled local HTTP API — no broker, no presence, no push. The User Agent and each MM run AXL as a Go sidecar; they peer by ed25519 pubkey published as an ENS text record. No DNS for agents.
Identity: ENS on Sepolia. Each MM owns a subname under parley.eth (mm-1.parley.eth, mm-2.parley.eth) carrying addr, axl_pubkey, agent_capabilities, and reputation_root. Verifying an offer cross-references the AXL sender pubkey against the resolved axl_pubkey AND recovers the EIP-712 signature against the resolved addr — message-claimed identity is never trusted.
Reputation: 0G Storage. Every settled trade writes a JSON TradeRecord blob; downloads verify a Merkle proof against the indexer's commitment. Scores are derived on-demand by replaying records — nothing on-chain except the latest reputation_root ENS pointer.
Agent: Hermes + MCP. The User Agent is Hermes (Nous Research) with three custom MCP servers: axl-mcp (peer discovery, intent broadcast, inbox poll), og-mcp (ENS resolution, 0G read/write, Uniswap reference quoting, settlement-state polling, wallet balances), and tg-mcp (Mini App web_app button rendering — Hermes' default Telegram adapter doesn't render those, so we call the Bot API directly). The LLM is Claude API; we tested 0G Compute but its broker SDK is ESM-broken (we used createRequire as a workaround for blob uploads, then deferred 0G Compute to a future proxy) and Hermes function-calling is more reliable on Claude.
Settlement: asymmetric submission. The User Agent is a calldata builder, not a wallet — it never holds funds and never sends transactions. User-side lockUserSide and settle are submitted from the user's wallet inside the Mini App via wagmi.writeContract. The MM side runs viem from a hot wallet. This keeps the trust model honest.
Fallback: Uniswap v3 on-chain. Sepolia's Uniswap pools aren't indexed by the Trading API gateway, so we call QuoterV2 and SwapRouter02 directly. The same quote anchors the "vs Uniswap" delta shown on every peer offer card.
Notable hacks. (1) Disabled Hermes' default memory toolset after observing session_binding leak across Telegram users via a single global MEMORY.md — a real cross-user wallet-address leak in production. (2) Inline-patched Hermes' session.py at container entrypoint time to always emit User ID: so the agent can resolve chat_id reliably. (3) Sepolia public RPCs drop eth_newFilter handles between polls, so we replaced viem.watchContractEvent with getContractEvents polling. (4) Derive each MM's AXL pubkey directly from its ed25519 PEM (last 32 bytes of the SPKI DER, verified to match axl-node's /topology our_public_key) so the register-mm script doesn't need a running AXL node. (5) Chain-as-truth doctrine: relay callbacks are hints, on-chain Settlement.getState(dealHash) is the guarantee — we treat polled state, not message timing, as the trigger for /settle and /refund.
Partner tech net. Hermes / Nous (agent runtime), Gensyn AXL (transport), 0G Storage (reputation), ENS (identity), Uniswap v3 (fallback + reference price), Telegram Mini App + WalletConnect (signing surface), Claude API (LLM). Each one earns its keep — none are decoration.

