Skip to main content
Glama
README.md
# Slug Wallet

Give your terminal AI agent a guarded USDC wallet. It intercepts HTTP 402 paywalls, enforces budget limits, signs payments automatically, and works with any x402 service — today.

**Chain:** Base mainnet  
**Token:** USDC (`0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`)

---

## Why

AI agents hitting paywalled APIs either crash or need raw access to your credit card. Slug Wallet gives them a wallet with hard guardrails:

- **$2 daily limit, $0.02 per request** — fully configurable
- **Domain whitelist** — agent can only pay approved services
- **Local spend ledger** — tracks every payment, persists across restarts
- **Plugs into Claude Code, OpenCode, any MCP client** — one command
- **Works with real x402 services right now** — Exa, Otto AI, Tavily, and more

No funds move until the firewall approves the payment. If a request falls outside your limits, the agent gets a clear error and nothing is signed.

---

## Quickstart

### 1. Connect to your agent

**Claude Code:**

```bash
claude mcp add slug-wallet -s user -- npx slug-wallet-mcp
```

**OpenCode** (`opencode.json` in your project root):

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "slug-wallet": {
      "type": "local",
      "command": ["npx", "slug-wallet-mcp"],
      "enabled": true
    }
  }
}
```

### 2. Pick a mode

**Dev mode** (no real money — for testing):

```json
{
  "env": { "SLUG_WALLET_DEV_SIGNER": "1" }
}
```

**Live mode** (real USDC on Base):

```json
{
  "env": {
    "CDP_API_KEY_ID": "your-key-id",
    "CDP_API_KEY_SECRET": "your-key-secret",
    "CDP_WALLET_SECRET": "your-wallet-secret"
  }
}
```

### 3. Try it

Ask your agent:

> *Fetch https://x402.ottoai.services/crypto-news using the slug-wallet tool*

The agent will call `slug_fetch`, Slug Wallet intercepts the 402, checks the firewall, signs the payment, and returns the content. All automatic.

---

## The firewall

Your `slug-config.json` controls exactly what the wallet is allowed to pay:

```json
{
  "maxUsdPerRequest": 0.02,
  "dailyUsdLimit": 2.00,
  "allowedDomains": ["exa.ai", "*.browserbase.com", "x402.ottoai.services"]
}
```

| Rule | What it does |
|------|-------------|
| `maxUsdPerRequest` | Blocks any single payment above this amount |
| `dailyUsdLimit` | Blocks all payments once the daily total is hit |
| `allowedDomains` | Blocks payments to any domain not in the list (supports `*.example.com` wildcards) |

The firewall runs **before** any signature. If a payment is blocked, the agent sees a clear error message explaining why — no funds move, no signature is generated.

Run `npx slug-wallet init` to create a `slug-config.json` with safe defaults.

---

## MCP tools

| Tool | What it does |
|------|-------------|
| `slug_fetch` | Make an HTTP request, auto-paying any 402 within firewall limits |
| `get_wallet_address` | Returns the signing wallet address |
| `get_daily_spend` | Returns `{ spentUsd, limitUsd, remainingUsd, pendingFeesUsd, pendingFeeCount }` |

---

## Real x402 services you can use today

These are live services that return HTTP 402 and work with Slug Wallet out of the box:

| Service | URL | Price | What it does |
|---------|-----|-------|-------------|
| Otto AI | `https://x402.ottoai.services/crypto-news` | $0.001 | Real-time crypto market news with sentiment |
| Otto AI | `https://x402.ottoai.services/trending-altcoins` | $0.001 | Top 3 trending altcoins |
| Exa Search | `https://api.exa.ai/search` | $0.007 | AI web search |
| Tavily | `https://x402.tavily.com/search` | $0.01 | Advanced web search |
| twit.sh | `https://x402.twit.sh/tweets/search` | $0.006 | Twitter/X tweet search |
| CoinGecko | `https://pro-api.coingecko.com/api/v3/x402/onchain/search/pools` | $0.01 | Onchain DEX pool data |
| Anchor | `https://api.anchor-x402.com/v1/price/token` | $0.001 | Token price lookup |

Add the domain to your `allowedDomains` and your agent can start paying for these immediately. Browse more at [x402scan.com](https://x402scan.com) or [agentic.market](https://agentic.market).

---

## Setup

### Getting CDP credentials (live mode)

1. Go to [portal.cdp.coinbase.com/projects/api-keys](https://portal.cdp.coinbase.com/projects/api-keys)
2. Create a Secret API key — copy `CDP_API_KEY_ID` and `CDP_API_KEY_SECRET`
3. Go to Wallets → Non-custodial → Security for `CDP_WALLET_SECRET`
4. Fund your agent wallet with USDC on Base (start with $2)

KYC is required for live accounts. Until KYC is complete, use dev mode.

### Environment variables

| Variable | Required | Description |
|----------|----------|-------------|
| `CDP_API_KEY_ID` | Live mode | Coinbase CDP API key ID |
| `CDP_API_KEY_SECRET` | Live mode | Coinbase CDP API key secret |
| `CDP_WALLET_SECRET` | Live mode | Coinbase CDP wallet secret |
| `SLUG_WALLET_DEV_SIGNER` | Dev mode | Set to `1` for fake signatures (no real payments) |
| `SLUG_WALLET_CONFIG_PATH` | Optional | Path to `slug-config.json` (default: `./slug-config.json`) |

The server hard-fails at startup if neither CDP credentials nor `SLUG_WALLET_DEV_SIGNER=1` is set.

---

## Library usage

Use Slug Wallet programmatically without MCP:

```ts
import { createSlugFetch, CdpPaymentSigner } from "slug-wallet";

const signer = new CdpPaymentSigner();
const slugFetch = await createSlugFetch({ signer });

const response = await slugFetch("https://x402.ottoai.services/crypto-news");
```

Bring your own signer by implementing `PaymentSigner`:

```ts
import type { PaymentSigner, InvoicePayload, PaymentProof } from "slug-wallet";

class MySigner implements PaymentSigner {
  async getAddress(): Promise<string> { ... }
  async signInvoice(invoice: InvoicePayload): Promise<PaymentProof> { ... }
}
```

The `PaymentSigner` interface is wallet-agnostic. `CdpPaymentSigner` (Coinbase CDP) ships built-in, but you can implement it with any EVM wallet provider — Privy, Fireblocks, local private keys, HSMs, etc. The firewall, interceptor, MCP server, and fee settlement layer work identically regardless of where the signature comes from.

---

## Verify

```bash
npm run check          # TypeScript build + 67 unit tests
npm run verify:harness # End-to-end interceptor + MockSigner
npm run verify:mcp     # End-to-end MCP subprocess (all 3 tools)
```

---

## For protocol operators

<details>
<summary>Setting up the fee settlement layer (optional)</summary>

Slug Wallet supports an on-chain fee settlement layer. When enabled, every payment generates a separate fee authorization that is batched and submitted to a `SlugSettlement` contract on Base, routing a percentage of each payment to a treasury wallet.

### How it works

```
Agent pays merchant via normal x402 flow
         │
         ├──► Merchant gets paid (normal)
         │
         └──► Slug Wallet signs fee authorization
                  │
                  ▼
           FeeQueue (.slug-wallet/fee-queue.json)
                  │ when total >= $0.05
                  ▼
           Relay (slug-wallet-relay)
                  │
                  ▼
           SlugSettlement.settleFee() on Base
                  │
                  ├──► Fee goes to treasury
                  └──► Settlement event emitted
```

### Configuration

In `slug-config.json`:

```json
{
  "settlement": {
    "enabled": true,
    "contractAddress": "0x...",
    "feeBps": 50,
    "treasuryAddress": "0x..."
  }
}
```

- `feeBps`: Fee in basis points (50 = 0.5%, 500 = 5%)
- `contractAddress`: Deployed `SlugSettlement` address on Base
- `treasuryAddress`: Where fees land (must be set when enabled)

### Running the relay

```bash
npx slug-wallet-relay
```

| Variable | Required | Description |
|----------|----------|-------------|
| `SLUG_RELAY_PRIVATE_KEY` | Yes | Private key of a Base wallet with ETH for gas |
| `SLUG_RELAY_AUTH_TOKEN` | Yes | Secret token shared with the MCP server |
| `SLUG_RELAY_PORT` | Optional | Port to listen on (default: `4022`) |
| `SLUG_WALLET_RELAY_URL` | MCP server | URL of the relay (e.g. `http://127.0.0.1:4022`) |

The relay binds to `127.0.0.1` only. Fund the relay wallet with ~$2 of ETH on Base for gas.

### Fee queue economics

Fees accumulate locally in `.slug-wallet/fee-queue.json`. When the total crosses `$0.05`, the MCP server batches them to the relay, which submits a single on-chain transaction:

```
50 payments at $0.001 each
  = $0.05 queued fees
  = 1 on-chain tx (~$0.01 gas)
  = $0.04 net to treasury per batch
```

### Settlement contract

The Solidity contract is in `contracts/SlugSettlement.sol`. Deploy with:

```bash
forge create --rpc-url https://mainnet.base.org \
  --private-key $RELAY_PRIVATE_KEY \
  contracts/SlugSettlement.sol:SlugSettlement \
  --constructor-args <treasury-address> <feeBps>
```

The contract has two functions:
- `executePayment()` — full payment routing (merchant + fee split in one transaction)
- `settleFee()` — fee-only settlement (used by the relay in dual-signing mode)

</details>

---

## License

MIT