Agentic Wallet
The agentic wallet is the architecture behind agent mode in the Doma CLI. It lets an AI agent execute on-chain actions on the user's behalf (within a hard policy) without ever holding the wallet's private key.
This page describes the model. For the user-facing CLI flow, see Wallet Modes.
What it is
Doma's launchpad uses Privy embedded wallets. Each user has an EVM wallet whose private key is generated and held inside Privy's HSM. Neither the user nor Doma ever see it. The wallet is available across both Doma Mainnet (chain 97477) and Doma Testnet (chain 97476); agent mode works on either.
For agent commerce, we attach a delegated agent signer to the wallet, governed by a per-wallet policy. The agent never holds the user's key, and Privy refuses any signature request that falls outside the policy.
Authority model

The policy doma-agentic-wallet-v1 is what makes the agent signer safe. Where <Doma chain IDs> in the diagram resolves to 97477 (mainnet) and 97476 (testnet), and <Doma testnet> is 97476 alone. Typed-data signatures are scoped to testnet today (see Known limitation).
The wallet's own private key stays in Privy's HSM. It signs every transaction (so on-chain validators see
from = wallet_address).The agent authorization key lives server-side in Doma's launchpad infra. It does not sign transactions itself; it tells Privy "this user authorized me, please sign on their behalf."
The policy is enforced by Privy. Anything the agent requests outside the policy is rejected before signing.
Policy fields
chain_allowlist
Which chain IDs the agent can target
Doma mainnet, Doma testnet, Base
method_allowlist
Which RPC methods the agent can call
eth_sendTransaction, eth_signTypedData_v4
usd_spend_ceiling
Cumulative USD spend before the agent must re-authorize
$200
allowance_window
Refill window for the spend ceiling
rolling 24h
revocable_by_user
User can detach the signer at any time
true
The defaults above describe Doma's doma-agentic-wallet-v1 policy. Future versions may tighten or relax fields.
Session lifecycle
Login
User runs doma auth login. The CLI opens a localhost callback URL in the user's browser, which loads Doma's launchpad consent screen.
The launchpad calls Privy's wallets.update() to attach the agent authorization key as an additional signer with the doma-agentic-wallet-v1 policy, then mints a short-lived session JWT keyed to a fresh allowance row in KV (default $200 budget).
The CLI persists the JWT to ~/.doma/credentials.json (mode 0600).
Sessions are network-scoped. To authorize agent mode on both Doma Mainnet and Doma Testnet, run doma auth login once per network (toggle the network with the --testnet flag or doma config set testnet <bool> between runs).
Use
Every CLI write command POSTs the session JWT plus the intended transaction payload to the launchpad's /api/agent/execute endpoint. The launchpad:
Validates the JWT.
Decodes the calldata, computes the USD value of the transaction (using oracle prices).
Checks the policy: chain allowed? method allowed? cumulative spend within ceiling?
If all checks pass, instructs Privy to sign on behalf of the user.
Submits the signed transaction to the chain RPC.
Decrements the allowance row by the USD value.
If any check fails, the launchpad returns a structured error and the CLI surfaces it cleanly to the user.
Revoke
User runs doma auth revoke. The launchpad calls Privy's removeSigners to detach the agent authorization key from the user's wallet, deletes the allowance row, invalidates the session JWT, and clears ~/.doma/credentials.json.
The user can also revoke from the launchpad's "Authorized agents" panel. Useful if the CLI machine is lost or compromised.
The three signing paths
A given Doma CLI action falls into one of three patterns based on what kind of signature it needs:
marketplace buy, swap, bridge, dns set, subdomain claim
eth_sendTransaction
wallet's own key (via Privy)
✅ working
marketplace cancel --type on-chain
eth_sendTransaction
wallet's own key
✅ working
marketplace offer, listing, off-chain cancel
eth_signTypedData_v4
agent authorization key, not the wallet
⚠️ off-chain signature limitation
The first two rows are "transactions": they're submitted on-chain and validators only care about from = wallet_address, which is true.
The third row is "off-chain typed data" used by gasless protocols like Seaport. The signing address must equal the wallet address. Today Privy uses the agent authorization key for these, so the signing address ≠ the wallet address, and Seaport rejects the signature.
Known limitation
Gasless typed-data flows (marketplace offer, listing, off-chain cancel) don't work in agent mode today. Workaround: use private-key mode for those specific actions.
The path forward is a smart-wallet migration: instead of the user's EOA, the wallet becomes a smart contract that validates signatures via on-chain logic (ERC-1271). The contract can be programmed to accept signatures from the agent authorization key as if they were the wallet's own. This eliminates the off-chain asymmetry entirely.
Tracked separately; not in scope for V1 of agent mode.
Security posture
Agent mode is a guardrail, not a vault. The policy bounds blast radius, but a compromise of the launchpad's agent authorization key or the user's session JWT still allows actions within the policy. Use a dedicated wallet for agent mode and keep the spend ceiling tight.
The launchpad's agent authorization key is rotated on a schedule and stored in HSM-backed cloud KMS. Compromise requires breaching both Privy and the launchpad infra.
Session JWTs are short-lived and tied to a specific wallet + allowance row. Theft of a JWT bounds the attacker by the remaining ceiling.
The user's wallet key remains in Privy's HSM at all times. Even an attacker with full launchpad access cannot exfiltrate it.
What's next
Wallet Modes: user-facing flow for
agentvsprivate-key.Commands → coverage matrix: per-command status of agent-mode support.
ERC-1271 specification: the migration target for gasless flows.
Last updated