# Giving an AI agent a wallet without giving it your keys

> Source: <https://dev.to/ahmad_shawar_de8d35d546cf/giving-an-ai-agent-a-wallet-without-giving-it-your-keys-407k>
> Published: 2026-11-01 20:41:25+00:00

Agents are starting to pay for things. An agent buying API credits, renting a GPU for an hour or paying for a dataset is no longer a thought experiment, and x402 (HTTP `402 Payment Required` with on-chain payment) makes it a normal web request.

That leaves the question of how the agent holds money.

**Give the agent a private key.** It works until a prompt injection, a bug or a leaked environment file. Then the wallet is empty, and there is nothing between the key and the funds.

**Approve every payment by hand.** Safe, and it removes the reason to use an agent.

What people actually want is what they already do with a company card: a limit per purchase, a monthly budget, a list of places it works, and a phone call for anything unusual.

The limits have to live somewhere the agent, and the machine it runs on, can't change. A smart contract is a good fit: the rules are checked by every node, and changing them needs the owner's key.

[Purser](https://github.com/ahmad-codex/purser) is an ERC-4337 smart account built for this. The owner grants each agent a session key with a policy:

Inside the policy, the agent pays on its own. Over the limit, the payment becomes an approval request, and it runs only if the owner co-signs. One transaction revokes a key or freezes the whole account.

If the agent's key leaks, the damage is bounded: the rest of the current budget, at allowed places, until you revoke it.

ERC-4337 splits an operation into validation and execution, and validation is not allowed to read the clock (ERC-7562), because bundlers have to be able to simulate it reliably. A daily budget is all about the clock.

So the checks are split:

`executeUserOp`, where reading the block time is fine.
Two smaller rules that matter: an owner approval raises the amount but never the scope, so an approved payment still has to be to an allowed place; and a revoke earlier in a bundle still stops a later operation in the same bundle.

Unit tests aren't enough for this. Purser has 41 unit tests through a real EntryPoint, fuzz tests that compare random payment and time sequences against a simple model of the budget, and invariant tests that throw thousands of random calls at the account and check three properties after each one: no spending over budget without approval, no funds moved by a revoked key, no policy change without the owner. Slither runs in CI.

It's still early and not audited, which is why everything below runs on a local chain.

An MCP server exposes six tools: `wallet_status`, `send_eth`, `send_token`, `call_contract`, `get_request` and `list_requests`. Each payment returns one of three outcomes, written for the model: done with the budget left, waiting for the owner with a request id, or refused with a reason it can act on.

```
docker run --rm -it -p 127.0.0.1:8787:8787 ghcr.io/ahmad-codex/purser:demo
```

Open [http://localhost:8787](http://localhost:8787). The container starts a local chain, deploys everything, and plays the agent story while the console updates. Then connect your own agent:

```
claude mcp add --transport http purser http://localhost:8787/mcp
```

and ask it to pay the merchant 0.3 ETH.

The [roadmap](https://github.com/ahmad-codex/purser/blob/main/ROADMAP.md) starts with paying x402 endpoints within the budget, a gas budget per key and EIP-7702 support. It's MIT licensed, and there are good first issues open. If you let agents spend money today, I'd like to hear how you limit it.
