AI Agents

AI agent wallet guide: key management and security

How to give an AI agent a wallet safely. MPC wallets, smart contract wallets, spending limits, and guardrails for production agents on Base.

14 minUpdated 2026-03-02

An AI agent without a wallet is a chatbot. An AI agent with a wallet and no guardrails is a liability. This guide is about the space between — making your agent autonomous enough to be useful without making it dangerous enough to drain your funds.

Every team building onchain agents eventually faces the same question: how do I let this thing sign transactions without giving it the keys to everything?

Here's what we've learned from building and watching others build on Base.

The risk spectrum

Before choosing an approach, understand where you sit:

LOW RISK                                          HIGH RISK
├──────────┼──────────┼──────────┼──────────┼──────────┤
Read-only    Testnet     Small       Moderate     Full
agent        txs only   budget      autonomy     autonomy
             ($0)       (<$500)     (<$10K)      (>$10K)
                    
Approach:    Approach:  Approach:   Approach:    Approach:
No wallet    Hot wallet MPC wallet  Smart        Multi-sig +
needed       throwaway  + limits    contract     timelock +
                                    wallet       human approval

Most agents should live in the middle. If you're starting out, target the "small budget with MPC wallet" zone. You can always expand autonomy once you trust your system.

What is MPC?

Multi-Party Computation splits the private key into shares held by different parties. No single party — not you, not Coinbase, not the agent — ever holds the complete key. Transactions require multiple shares to sign.

If your agent's server gets compromised, the attacker can't steal funds without Coinbase's key share.

Implementation with Coinbase CDP

typescript
import { CdpWalletProvider } from "@coinbase/agentkit";

const config = {
  apiKeyName: process.env.CDP_API_KEY_NAME,
  apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY,
  networkId: "base-mainnet",
  cdpWalletData: existingWalletData || undefined,
};

const walletProvider = await CdpWalletProvider.configureWithWallet(config);
const agentAddress = walletProvider.getAddress();

// Export wallet data for persistence
const walletData = await walletProvider.exportWallet();

Setting up spending policies

typescript
const policy = {
  rules: [
    {
      type: "contract_allowlist",
      contracts: [
        "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD", // Uniswap Router
        "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC
      ]
    },
    {
      type: "spending_limit",
      amount: "500",
      period: "daily"
    }
  ]
};

Pros and cons

Pros: No single point of key compromise. Spending policies enforced at infrastructure level. Easy integration with LangChain, CrewAI, ElizaOS via AgentKit. Wallet persists across agent restarts.

Cons: Dependency on Coinbase infrastructure. API rate limits for high-frequency agents. Not fully self-custodial. Costs scale with transaction volume.

Approach 2: smart contract wallets (best programmable guardrails)

Why smart contract wallets?

A smart contract wallet is code, not just a key. You can program rules directly into the wallet: spending limits, allowlisted contracts, time delays, multi-sig requirements — enforced onchain.

The difference matters. Application-level guardrails can be bypassed if the agent's server is compromised. Onchain guardrails can't — they're enforced by the blockchain itself.

Option A: Safe (formerly Gnosis Safe)

The most battle-tested smart contract wallet. Used by DAOs and treasuries managing billions.

python
from safe_eth.safe import Safe
from web3 import Web3

w3 = Web3(Web3.HTTPProvider("https://mainnet.base.org"))

safe = Safe.deploy(
    w3,
    owners=[
        agent_address,      # Agent can propose transactions
        human_address,      # Human approves high-value ones
    ],
    threshold=1,            # 1 signature for low-value
)

Guard modules add programmable restrictions:

solidity
contract AgentGuard {
    uint256 public dailyLimit = 500e6;  // 500 USDC
    uint256 public spentToday;
    mapping(address => bool) public allowedTargets;
    
    function checkTransaction(
        address to,
        uint256 value,
        bytes memory data
    ) external {
        require(allowedTargets[to], "Target not allowed");
        require(spentToday + value <= dailyLimit, "Daily limit exceeded");
        spentToday += value;
    }
}

Option B: ERC-4337 account abstraction wallets

Account abstraction wallets (Kernel, ZeroDev, Biconomy) give you the most flexibility. Session keys are the killer feature for agents — create a limited-permission key that can only call specific contracts, spend up to a limit, and expire after a time period.

typescript
const sessionKeyPermissions = {
  allowedContracts: ["0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD"],
  allowedFunctions: ["execute(bytes,bytes[],uint256)"],
  spendingLimit: parseUnits("100", 6), // 100 USDC
  validUntil: Math.floor(Date.now() / 1000) + 86400, // 24 hours
};

The agent operates with the session key. If compromised, the attacker can only do what the session key allows — limited contracts, limited amounts, automatic expiry.

Base App and smart wallets

Base App (called "Base" on app stores, replaced Coinbase Wallet) uses smart wallet infrastructure natively. If your agent serves end users through Base App, the smart wallet integration is already there — users get passkey authentication and gasless transactions. You can build mini apps with MiniKit SDK (npx create-onchain --mini) that run inside Base App and other Farcaster clients. See our Base App integration guide for details.

Approach 3: hot wallet with application-level guards

The simplest approach. Generate a private key, store it encrypted, and implement guards in your application code.

python
from eth_account import Account
from web3 import Web3
import json, os

def get_agent_wallet():
    keyfile = "agent_wallet.json"
    if os.path.exists(keyfile):
        with open(keyfile) as f:
            encrypted = json.load(f)
        key = Account.decrypt(encrypted, os.environ["WALLET_PASSWORD"])
        return Account.from_key(key)
    else:
        acct = Account.create()
        encrypted = acct.encrypt(os.environ["WALLET_PASSWORD"])
        with open(keyfile, 'w') as f:
            json.dump(encrypted, f)
        return acct

When this makes sense: Testnet development. Very small budgets (under $100). Agents that primarily read data and rarely transact. Prototyping.

Why it's risky: If your server is compromised, the attacker gets the encrypted key. If they also get the password from environment variables or memory, they have full control. No second layer of defense.

Rule of thumb: Never put more in a hot wallet than you'd carry in cash in your physical wallet.

The guardrail stack: defense in depth

Production agents need multiple layers:

Layer 1: LLM prompt guardrails

Tell the LLM what it can and can't do. Reliability: Low. LLMs can be jailbroken. Never sufficient alone.

Layer 2: application-level guards

Your code validates every transaction before signing: contract allowlist, value limits, slippage limits, gas sanity checks, rate limiting.

python
class TransactionGuard:
    def __init__(self):
        self.daily_limit_usd = 500
        self.single_tx_limit_usd = 100
        self.allowed_contracts = {
            "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD",  # Uniswap
            "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",  # USDC
        }
    
    def check(self, tx) -> tuple[bool, str]:
        if tx.to.lower() not in {c.lower() for c in self.allowed_contracts}:
            return False, f"Contract {tx.to} not in allowlist"
        value_usd = self.get_usd_value(tx.value)
        if value_usd > self.single_tx_limit_usd:
            return False, f"TX value ${value_usd} exceeds limit"
        return True, "Approved"

Reliability: Medium. Stops most mistakes. Bypassable if server is compromised.

Layer 3: wallet-level enforcement

MPC policies or smart contract guards enforce limits at the signing/execution layer. Can't be bypassed by application-level compromises.

Layer 4: circuit breakers

python
class CircuitBreaker:
    def __init__(self):
        self.portfolio_start = get_portfolio_value()
        self.max_drawdown_pct = 5
        self.consecutive_errors = 0
    
    def check(self):
        current = get_portfolio_value()
        drawdown = (self.portfolio_start - current) / self.portfolio_start * 100
        if drawdown > self.max_drawdown_pct:
            self.halt_agent("Portfolio drawdown exceeded threshold")
            alert_human(f"CIRCUIT BREAKER: {drawdown:.1f}% drawdown")
            return False
        return True

Layer 5: human-in-the-loop

For high-value actions, send a notification and wait for approval:

  • Under $50: auto-execute
  • $50-$500: notify, execute after 5-minute timeout unless stopped
  • Over $500: require explicit human approval

Token approvals: the silent killer

The most common way agents leak value isn't through bad trades — it's through unlimited token approvals.

python
# DANGEROUS: unlimited approval
usdc.functions.approve(spender, 2**256 - 1).transact()

# SAFE: exact amount approval
usdc.functions.approve(spender, exact_amount_needed).transact()

Rules for agent approvals:

  1. Never approve MAX_UINT256. Approve the exact amount needed.
  2. Revoke approvals after each transaction if possible.
  3. Monitor approvals with tools like Revoke.cash.
  4. Include approval checks in your guardrails — block any transaction that would set an unlimited approval.

Monitoring your agent's wallet

Build the best guardrails in the world and still lose money if you're not watching.

Real-time alerts

  • Every transaction the agent sends (success and failure)
  • Balance drops below threshold
  • Interactions with unknown contracts
  • Failed transactions (often indicate bugs or changed contract state)

Data sources

  • Direct RPC monitoring: Watch your agent's address
  • Sonarbot: Monitor the broader market — whale movements and smart money on Base can signal changing conditions before your agent makes a bad trade
  • Checkr: Real-time token insights for tokens your agent trades
  • Basescan: Transaction history and contract interactions
  • Dune dashboards: Custom queries for your agent's onchain activity

The decision matrix

ApproachSecurityComplexityCostBest For
Hot walletLowLowFreeTestnet, prototyping
Coinbase MPCHighMediumAPI costsMost production agents
Smart contract walletHighestHighDeploy costHigh-value, full autonomy
MPC + Smart walletHighestHighestBothInstitutional / high-stakes

Our recommendation for most builders: Start with Coinbase MPC wallet via AgentKit. It gives you production-grade security with minimal complexity. Graduate to a smart contract wallet when your agent manages significant value or needs programmable onchain guardrails.

Bankr and Virtuals: platform-managed wallets

If you're building on Bankr or Virtuals, the platform handles wallet infrastructure. You don't manage keys directly — the platform provides the agent with trading capabilities within their system.

This is a valid approach for agents that operate within these ecosystems. The trade-off: you're trusting the platform's security model instead of managing your own. For many use cases, this is the right call — the platform has invested far more in wallet security than most individual teams can.

Checklist before going to mainnet

  • Testnet first: Run on Base Sepolia for at least a week with real decision logic
  • Fund minimally: Start with the minimum capital needed. Scale up after trust is established.
  • Guard every layer: Prompt, application, wallet, circuit breaker, human
  • Exact approvals: No MAX_UINT256. Ever.
  • Kill switch: Can you stop the agent and withdraw funds in under 5 minutes?
  • Logging: Every transaction logged with the agent's reasoning
  • Alerts: Real-time notification for every transaction and any anomaly
  • Backup plan: If the agent goes rogue at 3 AM, what happens?
  • Incident runbook: Document exactly what to do if something goes wrong

The agents that survive are the ones built by paranoid builders. Assume everything will go wrong. Then build so it doesn't matter when it does.


Ready to build? Start with our complete agent launch guide or compare agent frameworks to pick your stack.