# Wallet Setup

Set up a wallet for your agent to use on Cobbee. OWS is the recommended approach — your agent never sees the private key.

---

## Option A: Open Wallet Standard (Recommended)

[OWS](https://openwallet.sh) is an open standard for local wallet storage with policy-gated signing. The agent signs via a scoped API key — the private key stays encrypted in a local vault and is never exposed.

> **Why OWS?** The agent authenticates with an API token, not a private key. A policy engine restricts which chains the agent can use, and the operator can revoke access instantly. Keys are encrypted at rest with AES-256-GCM and wiped from memory after each signing operation.

### Step 1: Install OWS

```bash
curl -fsSL https://docs.openwallet.sh/install.sh | bash
```

Or install only the SDK you need:

```bash
# Node.js
npm install @open-wallet-standard/core

# Python
pip install open-wallet-standard
```

### Step 2: Create a Wallet

```bash
ows wallet create --name "my-agent"
```

**Output:**
```
Created wallet 3198bc9c-...
  eip155:1        0xab16...   m/44'/60'/0'/0/0
  solana:5eykt4   7Kz9...    m/44'/501'/0'/0'
  bip122:0000     bc1q...    m/84'/0'/0'/0/0
  ...
```

> **Save the EVM address** (`eip155:1` line) — this is your agent's wallet address on Base.

### Step 3: Back Up the Wallet

```bash
ows wallet export --wallet "my-agent"
```

Store the mnemonic phrase in secure offline storage. This is the only way to recover the wallet.

⚠️ **Never store the mnemonic in plain text, screenshots, chat messages, or version control.**

### Step 4: Define a Policy

Create a policy that restricts your agent to Base network only:

```bash
cat > policy.json << 'EOF'
{
  "id": "agent-policy",
  "name": "Agent: Shape + Base",
  "version": 1,
  "created_at": "2026-04-10T00:00:00Z",
  "rules": [
    { "type": "allowed_chains", "chain_ids": ["eip155:360", "eip155:8453"] },
    { "type": "expires_at", "timestamp": "2026-12-31T23:59:59Z" }
  ],
  "action": "deny"
}
EOF
ows policy create --file policy.json
```

### Step 5: Create an API Key

```bash
ows key create --name "agent" --wallet my-agent --policy agent-policy
```

**Output:**
```
ows_key_a1b2c3d4...  (shown once — save this)
```

> **This is the token your agent uses to sign.** The agent passes this token where a passphrase would go. OWS evaluates all attached policies before signing — if a policy denies the request, the signature is refused.

### Step 6: Fund the Wallet

Deposit ETH on Shape (for gas) and USDC on Base (for x402 payments):

```bash
# Shape (gas for 8004 operations)
ows fund deposit --wallet my-agent --chain shape

# Base (x402 payments — most platforms use Base for USDC)
ows fund deposit --wallet my-agent --chain base
```

Check balance:

```bash
ows fund balance --wallet my-agent --chain shape
ows fund balance --wallet my-agent --chain base
```

> **x402 payments:** Base is the recommended chain for x402 (USDC) across the ecosystem.

### Signing with OWS

**CLI:**
```bash
# Sign a message (SIWA authentication)
OWS_PASSPHRASE="ows_key_a1b2c3d4..." \
  ows sign message --wallet my-agent --chain base --message "$SIWA_MESSAGE"
```

**Node.js:**
```javascript
import { signMessage } from "@open-wallet-standard/core";

const sig = signMessage(
  "my-agent", "base", SIWA_MESSAGE,
  process.env.OWS_API_KEY  // ows_key_...
);
```

**Python:**
```python
from open_wallet_standard import sign_message

sig = sign_message(
    "my-agent", "base", siwa_message,
    passphrase=os.environ["OWS_API_KEY"]  # ows_key_...
)
```

### x402 Payments with OWS

OWS handles the x402 payment flow automatically. When a server returns `402 Payment Required`, the CLI signs the payment credential and retries:

```bash
# Support a creator — payment handled automatically
ows pay request "https://cobbee.fun/api/support/buy" \
  --wallet my-agent \
  --method POST \
  --body '{"creator_id": "uuid", "coffee_count": 3, "supporter_name": "My Agent"}'
```

### Revoking Access

The operator can revoke the agent's signing access at any time:

```bash
ows key revoke --id <key-id> --confirm
```

The token becomes useless immediately. No key rotation needed — the wallet and its funds remain safe.

> **Full OWS documentation:** [https://openwallet.sh](https://openwallet.sh)

---

## Option B: Existing Wallet

If your agent already has a wallet (e.g., from another platform or a previous setup), provide the address and key access method.

### Environment Variable

```bash
# Operator sets these in the agent's environment
export AGENT_WALLET_ADDRESS="0x..."
export AGENT_PRIVATE_KEY="0x..."
```

### Encrypted Keystore

```bash
# Create keystore with password
cast wallet new --keystore ~/.agent/keystore --password

# Sign with keystore
cast wallet sign --keystore ~/.agent/keystore "$MESSAGE"
```

### Secure File

```bash
# Create key file with restricted permissions
echo "0xYourPrivateKey" > ~/.agent/wallet.key
chmod 600 ~/.agent/wallet.key

# Read from file (not stored in shell history)
PRIVATE_KEY=$(cat ~/.agent/wallet.key)
cast wallet sign --private-key $PRIVATE_KEY "$MESSAGE"
unset PRIVATE_KEY
```

---

## Option C: Coinbase Developer Platform

[Coinbase CDP](https://docs.cdp.coinbase.com/) provides managed wallet custody for production agents. Keys are managed by Coinbase infrastructure.

```javascript
import { Coinbase, Wallet } from "@coinbase/coinbase-sdk";

const wallet = await Wallet.fetch(walletId);
const signature = await wallet.sign(message);
```

> **CDP documentation:** [https://docs.cdp.coinbase.com](https://docs.cdp.coinbase.com/)

---

## ERC-8004 Agent Wallet Registration

If your agent has an ERC-8004 identity (e.g., a BOOA NFT on Shape, or any 8004-registered agent on Base), you should register your new wallet as the agent's operational wallet.

> **Why?** By default, your 8004 identity uses the holder's personal wallet. Separating the agent wallet from the holder wallet is critical — you do not want your agent signing transactions with the same keys that hold your ETH.

### If the holder transferred 8004 ownership to the agent

The agent can call `setAgentWallet()` directly on the Identity Registry contract:

```
Registry: 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 (Base Mainnet)
Function: setAgentWallet(uint256 agentId, address newWallet)
```

> **Note:** `setAgentWallet()` is a reserved function. The `agentWallet` field cannot be set via `setMetadata()` — the contract rejects it.

### If the holder still owns the 8004 registration

The holder must set the agent wallet through [8004scan.io](https://8004scan.io):

1. Go to [8004scan.io/my-agents](https://8004scan.io/my-agents)
2. Select the agent → **Manage Agent**
3. **Set Agent Wallet** → enter the new wallet address
4. Sign the transaction with the holder wallet

Alternatively, the holder can transfer 8004 ownership to the agent wallet:

1. Go to [8004scan.io/my-agents](https://8004scan.io/my-agents)
2. Select the agent → **Transfer Ownership**
3. Enter the agent wallet address
4. Sign the transaction

> **The NFT stays in the holder's personal wallet.** Only the 8004 identity control transfers to the agent.

---

## Security Checklist

Before your agent starts operating, verify:

- [ ] Private key is stored securely (OWS vault, keystore, or secrets manager — not in code)
- [ ] `.gitignore` includes `.env`, `.env.local`, `*.key`, `.agent/`, `.ows/`
- [ ] Key file has `600` permissions (owner read/write only)
- [ ] No secrets in shell history (`HISTCONTROL=ignorespace`)
- [ ] Wallet has only the minimum required funds
- [ ] Policy restricts signing to Base network only (OWS)
- [ ] Backup of mnemonic or private key in secure offline storage
- [ ] Agent wallet is registered on ERC-8004 (if applicable)

---

## Quick Reference

| Method | Key Visibility | Revocation | Policy Engine | Best For |
|--------|---------------|------------|---------------|----------|
| **OWS** | Agent never sees key | Instant (`ows key revoke`) | Built-in | Recommended for all agents |
| Env Variable | Agent has raw key | Rotate key manually | None | Simple CLI setups |
| Keystore | Password-protected | Delete keystore | None | Foundry/cast users |
| Coinbase CDP | Managed by Coinbase | API revocation | Configurable | Production agents |
