x402-aa-wallet
The easiest way for an ERC-4337 / account-abstraction agent to pay x402 API calls — with a dedicated, non-custodial EOA, since its smart-wallet signature doesn't work with x402 yet.
A lightweight, typed SDK: generate a spend wallet, fund it from your agent's own smart wallet, and every request through it pays x402 (HTTP 402) challenges automatically — retried and returned, no manual handling — against any x402 merchant. Originally built for HoodGrow (see "Sponsored by" below), and works the same way against any other x402 API.
flowchart LR
A[AI Agent] --> B[Request API]
B --> C[402 Payment Required]
C --> D[x402_session pays automatically]
D --> E[Retry request]
E --> F[Response]
Features
- 🤖 Built for ERC-4337 / account-abstraction agents
- 💳 Automatic x402 payment handling — detect a 402, pay, retry, transparently
- 💰 Optional
max_amount_usdspend cap — a real enforcement boundary, not just a docs warning - 🔒 Non-custodial — the private key never leaves your process, and is excluded from
repr()(safe to log the wallet by accident) - ⚡ Minimal dependencies (
eth-account,requests,x402) - 🌐 Works against any x402-compatible API
- 📦 Fully typed
- 🟦 TypeScript implementation also available (see Related projects)
Installation
pip install x402-aa-wallet
Formerly published as
hoodgrow-x402-aa, importable ashoodgrow_x402_aa— same code, same maintainers, new name to reflect that it's a general-purpose x402 utility, not a HoodGrow-specific client. See "Sponsored by" below.
Quick start
from x402_aa_wallet import create_spend_wallet, get_usdc_balance, x402_session
# 1. Generate a dedicated spend wallet — locally, once.
wallet = create_spend_wallet()
print("fund this address:", wallet.address)
# store wallet.private_key yourself (env var / secret manager) — this
# library never sees it again after this call returns.
# 2. Fund `wallet.address` with a little USDC on Base — from your agent's
# own smart wallet, using its own transfer/send call (not this library).
# 3. Check the balance whenever you want to know if it needs topping up.
balance = get_usdc_balance(wallet.address)
# 4. Pay any x402 endpoint with it — payment happens automatically.
# max_amount_usd is optional but strongly recommended for autonomous
# use: it refuses to pay any single challenge above this amount
# instead of trusting whatever the server's 402 response asks for.
session = x402_session(wallet, max_amount_usd=0.5)
# First call: HoodGrow's own hello-world endpoint — $0.001, no API key, a
# real 402 challenge and settlement so you can watch the whole flow work.
ping = session.get("https://www.hoodgrow.com/api/agent/ping")
print(ping.json())
# Then: real data, same wallet, same call shape.
resp = session.get("https://www.hoodgrow.com/api/agent/token/NVDA")
print(resp.json())
Restarting your agent? Rehydrate the same wallet from the key you stored:
from x402_aa_wallet import spend_wallet_from_private_key
wallet = spend_wallet_from_private_key(YOUR_STORED_PRIVATE_KEY)
Why this exists
x402's "exact" EVM scheme settles payment via an EIP-3009 ECDSA signature, which an account-abstraction owner key (often a P256/WebAuthn passkey, or even secp256k1 but the wrong address) usually can't produce — full ERC-1271/ERC-6492 smart-wallet support is still an open, unshipped facilitator feature (see coinbase/x402#639). The fix is giving the agent a small, dedicated EOA it funds itself, purely for x402 spending. Full writeup: hoodgrow.com/blog/x402-account-abstraction-eoa.
Non-custodial — read this before using it
We never see your private key. Nobody does but you.
create_spend_wallet()generates a fresh secp256k1 keypair entirely inside your own process, usingeth_account. Nothing is transmitted, logged, or persisted by this library.- The private key is returned to you once, in memory. Store it yourself (env var, secret manager) — this library keeps no copy after the call returns.
SpendWalletexcludesprivate_keyfrom itsrepr()— direct attribute access (wallet.private_key) still works, butprint(wallet), an unhandled exception's traceback, or a logging call that stringifies the object won't show it.- Funding the spend wallet is your agent's job, using your agent's
own smart-wallet infrastructure. This library never moves funds itself —
it only tells you the address to send to and (via
get_usdc_balance) how much is there. - The published package is open source. Don't trust this description —
read
src/x402_aa_wallet/, it's short.
Spend cap
x402_session accepts max_amount_usd:
session = x402_session(wallet, max_amount_usd=0.10)
Without it, x402_session pays whatever a 402 response asks for — a
misbehaving or compromised merchant returning a much larger amount than
expected gets paid in full, silently. With max_amount_usd set, a payment
requirement above the cap is filtered out before signing (via a real
x402ClientSync policy, not a client-side amount check bolted on after
the fact), and if that leaves nothing payable, the request raises instead
of proceeding.
The cap only evaluates a requirement whose asset is a known 6-decimal Circle USDC deployment (Base mainnet or Base Sepolia) — anything else is excluded rather than evaluated with a guessed decimal count, since guessing wrong could make a genuinely large charge on a different-decimals asset look small enough to slip through.
API
| Function | Returns |
|---|---|
create_spend_wallet() |
A new SpendWallet(address, private_key, account) |
spend_wallet_from_private_key(key) |
Rehydrates a SpendWallet from a key you already have |
get_usdc_balance(address, rpc_url=DEFAULT_BASE_RPC_URL) |
USDC balance (float, human units) on Base |
x402_session(wallet, *, max_amount_usd=None, network=NETWORK) |
A requests.Session that auto-pays x402 challenges — wallet can be a SpendWallet, an eth_account LocalAccount, or a raw private key string. max_amount_usd — see "Spend cap" above; network overrides the default eip155:8453 (Base mainnet) |
get_usdc_balance talks to Base over plain JSON-RPC (eth_call) — no
web3.py dependency, one read-only call. Override rpc_url if you run
your own node.
Use cases
- AI assistants and copilots
- MCP servers
- Autonomous agents built on ERC-4337 smart wallets
- Multi-agent systems
- Research agents
- Trading bots
- Automation workflows
Payment safety
Every payment x402_session makes is real USDC on Base mainnet — not
reversible. Only fund the spend wallet with what you're willing to spend,
and never reuse an EOA that also holds funds you care about for anything
else. Set max_amount_usd (see "Spend cap" above) for any autonomous/agent
use — don't rely on funding discipline alone as the only safety boundary.
Sponsored by
Built and maintained by the team behind HoodGrow — stock token data for Robinhood Chain — to pay their own x402-protected API. Released as a standalone, general-purpose tool because the AA/x402 gap this solves isn't specific to HoodGrow.
Related projects
Once your agent has a wallet that pays for itself, the next step is an agent that already knows what to call:
- hoodgrow-mcp — an MCP server for HoodGrow's stock-token API. Free tier, no signup required for a key.
- x402-aa-wallet (TypeScript) — TypeScript implementation of this package
- x402 — the HTTP 402 payment protocol
Development
pip install -e ".[dev]"
pytest
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file x402_aa_wallet-0.2.1.tar.gz.
File metadata
- Download URL: x402_aa_wallet-0.2.1.tar.gz
- Upload date:
- Size: 12.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b869c432fd6bcf156fc763325850622d1f41397935e8e8c7f22459898bae9c10
|
|
| MD5 |
3db0db6f3c5ff9a40b23682085b0f22a
|
|
| BLAKE2b-256 |
784527da7bb0b3215fee5bc65cf8407bc20c63ad743108508f3b4cc379c49937
|
Provenance
The following attestation bundles were made for x402_aa_wallet-0.2.1.tar.gz:
Publisher:
publish.yml on MeMikko/hoodgrow-x402-aa
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
x402_aa_wallet-0.2.1.tar.gz -
Subject digest:
b869c432fd6bcf156fc763325850622d1f41397935e8e8c7f22459898bae9c10 - Sigstore transparency entry: 2386686318
- Sigstore integration time:
-
Permalink:
MeMikko/hoodgrow-x402-aa@4027b927ad575f963023ff7cb107719c767cb722 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/MeMikko
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4027b927ad575f963023ff7cb107719c767cb722 -
Trigger Event:
release
-
Statement type:
File details
Details for the file x402_aa_wallet-0.2.1-py3-none-any.whl.
File metadata
- Download URL: x402_aa_wallet-0.2.1-py3-none-any.whl
- Upload date:
- Size: 11.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9f8d02a427bc5e5a189b20ccc0fbd38ee890cb1089a900986630fc8e41e7e24c
|
|
| MD5 |
fcbf5083fdd1e96993c2fb73d12f6db7
|
|
| BLAKE2b-256 |
000c67c8d6659f40c1e5bbba7a2ed6d4ffab760cf30351e199a9c780fd623ae4
|
Provenance
The following attestation bundles were made for x402_aa_wallet-0.2.1-py3-none-any.whl:
Publisher:
publish.yml on MeMikko/hoodgrow-x402-aa
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
x402_aa_wallet-0.2.1-py3-none-any.whl -
Subject digest:
9f8d02a427bc5e5a189b20ccc0fbd38ee890cb1089a900986630fc8e41e7e24c - Sigstore transparency entry: 2386686326
- Sigstore integration time:
-
Permalink:
MeMikko/hoodgrow-x402-aa@4027b927ad575f963023ff7cb107719c767cb722 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/MeMikko
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4027b927ad575f963023ff7cb107719c767cb722 -
Trigger Event:
release
-
Statement type: