Search projects, hackathons, sponsors and tech

    ← All projects

    Ephemeral Wallet

    Disposable wallets that let AI agents spend within limits and refuse risky counterparties

    Demo

    About

    Ephemeral Agent Wallet gives an AI agent a temporary, narrowly scoped capability instead of a permanent wallet. If an agent holds a private key with full access to your funds, one bad prompt, hallucination or compromised dependency can drain everything. With this project, you issue the agent a "card": it can pay one merchant, up to a set budget and number of uses, until an expiry time. The smart contract enforces those limits, not the agent. The agent isn't even told its limits, so when it overspends, the card blocks the payment on-chain and the app shows it as Blocked with the reason. There are two kinds of card: - One-time card: a fresh EphemeralMissionWallet funded with just the budget. It allows one purchase, and cancelling it refunds whatever is left. This gives maximum isolation per mission. - Multi-use card: a revocable permission on your ReusablePermissionWallet. The agent can keep buying until the budget or uses run out, and revoking the card cancels only that permission. Multi-use cards also support plugins. The first one, ApprovalHook, holds any purchase above a threshold until you approve that exact purchase with Touch ID (a passkey whose P-256 signature is verified on-chain). The agent waits, you approve, and the purchase goes through. The agent itself is a CLI. You give it a task in plain language, like "buy two cinema tickets for tonight". Claude plans the order from the merchant's on-chain catalog, and the task is recorded on-chain as the purchase memo. On top of the cards, agents can pay each other over x402 in USDC, and every payment is screened live by the Intercepta API: - Before signing, the paying agent screens the payee, the token (real USDC or a lookalike) and the exact EIP-3009 authorization. A pure policy turns the results into PAY, CAP, HOLD or REFUSE, with reasons. USDC only moves on PAY or CAP: the wallet contract then approves the payment on-chain within the card's limits and validates the signature through ERC-1271. HOLD sends the payment to an owner inbox for approval. - The paid service runs its own facilitator. It scree owner and its agent before verifying or settling, soa clean agent working for a sanctioned owner still gets rejected. - Screening fails closed: any timeout, error or unexpe payment. It never counts as clean. - The web app also screens a merchant when you issue a card. Merchants come back Verified, Caution, Unverified or Blocked, and a Blocked merchant can't be issued a card. The demo runs end to end with one command (npm run demo) on an Anvil fork of Base Sepolia with real USDC. It includes three shop merchants, a Mount Fuji Weather x402 seller that agents pay with USDC cards, a web UI for issuing cards and watching activity, and scripted scenarios: a clean payment settles, a sanctioned payee is refused, a large payment is held for owner approval, and a payer with a sanctioned owner is rejected by the seller.

    How it's made

    EphemeralWallet is a TypeScript monorepo (npm workspaces) built around a Foundry project. The contracts come in two flavours. A one-time card is its own EphemeralMissionWallet, deployed and funded by a factory. A multi-use card is a permission on the owner's ReusablePermissionWallet: agent, merchant, budget, uses, expiry and asset. The wallet checks and consumes that permission before every call. Multi-use cards can also carry plugins, and the first one, ApprovalHook, holds large purchases until the owner approves them with Touch ID. The passkey signature is verified on-chain through the P-256 precompile, which meant running our Anvil fork of Base Sepolia with --hardfork osaka, since a fork doesn't get it by default. The agent is a Node CLI on viem. It reads the merchant's on-chain catalog, plans the order with Claude and pays with its card. It's never told its limits, so overspending attempts revert on-chain and show up in the React app (Vite, TanStack Router, wagmi, shadcn/ui) as Blocked with a decoded reason. The app has no backend database since all card state comes from contract events. For agent-to-agent payments we used x402 with real USDC on Base Sepolia. The fun part was making a smart contract the payer. x402 expects an EIP-3009 authorization signed by the payer, so the agent first calls approvePayment. That applies the card's limits, computes the exact EIP-712 digest on-chain and records it. The wallet's ERC-1271 check then approves only that digest and ignores the signature bytes, and we pass a dummy signature over 65 bytes on purpose so facilitators take the contract-signer path. Intercepta is what makes those payments safe rather than just bounded. Our @eaw/risk package is the only code that calls it. Before signing, the agent screens the payee, the token and the exact authorization. A pure policy function turns the results into PAY, CAP, HOLD or REFUSE, with Intercepta's trait reasons attached, and only PAY or CAP. On the other side, our x402 seller runs its own facilitator and screens the paying wallet, its owner and its agent before settling. It checks the payment signature first so garbage requests don't burn API quota. The chant check when you issue a card, through a small Vite dev-server endpoint so the API key never reaches the browser. Everything fails closed: a timeout or odd response is a refusal, never a pass. A few workarounds were needed. Intercepta only coverestnet payments by rewriting the EIP-712 domain toBase mainnet and mainnet USDC. Its message scan rated a transfer to a sanctioned address as Low, so we also screen the payee as an address. It 404s Anvil's default dev accounts, so our generates and funds fresh keys on every run with anvil_dealERC20.