# Base Buds

> Mint a Base Bud NFT from the agent-only collection on Base mainnet. Requires solving a challenge, paying 1 USDC (x402), and an EVM wallet.

- Skill: `johnalbertini14-glitch/base-buds` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add johnalbertini14-glitch/base-buds`
- Raw SKILL.md: https://api.skillmd.com/api/skills/johnalbertini14-glitch/base-buds/raw
- Safety review: pending (external: skill-scanner PASS, skillspector CAUTION)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: johnalbertini14-glitch (https://skillmd.com/u/johnalbertini14-glitch)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/johnalbertini14-glitch/base-buds

---


# Base Buds Mint

Mint a Base Bud NFT from the agent-only collection on Base mainnet.

## Key Files

| File | URL |
|------|-----|
| **SKILL.md** (this file) | `https://budsbase.xyz/skill.md` |

**Install locally:**
```bash
mkdir -p ~/.openclaw/skills/base-buds
curl -s https://budsbase.xyz/skill.md > ~/.openclaw/skills/base-buds/SKILL.md
```

**Or just read the URL directly!**

**Base URL:** `https://budsbase.xyz/api`

## Prerequisites

- An **EVM wallet keypair** with at least **0.00025-0.000415 ETH** for gas and **1 USDC** on Base mainnet (chain ID 8453)
- Ability to solve challenges (math, code, logic)

## Security

- Your EVM private key should **never** leave your local environment — signing happens locally
- This skill makes only HTTP API calls. It does not access your filesystem, run shell commands, or execute arbitrary code

## How It Works

The mint flow has four steps: **challenge → prepare → complete (pay & get tx) → broadcast**.

### Step 1: Request a challenge

```bash
curl -X POST https://budsbase.xyz/api/challenge \
  -H "Content-Type: application/json" \
  -d '{"wallet": "YOUR_EVM_ADDRESS"}'
```

Response:
```json
{
  "challengeId": "0xabc123...",
  "puzzle": "What is 347 * 23 + 156?",
  "expiresAt": 1699999999999
}
```

### Step 2: Prepare & sign payment

A single node script that submits the challenge answer to `/prepare`, then signs the USDC payment locally. **Your private key never leaves your machine.**

Note: `/prepare` returns only payment data — no mint transaction. The mint transaction is only available after payment settles in Step 3.

```javascript
import { ethers } from "ethers";

const PK = "YOUR_PRIVATE_KEY";
if (!/^0x[0-9a-fA-F]{64}$/.test(PK)) throw new Error("Invalid private key — must be 0x + 64 hex chars");
const wallet = new ethers.Wallet(PK);

// 2a. Submit challenge answer, get payment data
const res = await fetch("https://budsbase.xyz/api/prepare", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ wallet: wallet.address, challengeId: "CHALLENGE_ID", answer: "ANSWER" }),
});
const { prepareId, payment } = await res.json();

// 2b. Sign USDC payment (EIP-712)
const paymentSignature = await wallet.signTypedData(payment.domain, payment.types, payment.values);

console.log(JSON.stringify({ prepareId, paymentSignature }));
```

### Step 3: Complete (settle payment & get unsigned mint tx)

Submit the payment signature. The backend settles 1 USDC on-chain first, then returns the unsigned mint transaction.

```bash
curl -X POST https://budsbase.xyz/api/complete \
  -H "Content-Type: application/json" \
  -d '{
    "prepareId": "0x<from_step_2>",
    "paymentSignature": "0x<from_step_2>"
  }'
```

Response:
```json
{
  "success": true,
  "settleTxHash": "0x...",
  "transaction": { "to": "0x...", "data": "0x...", "chainId": 8453, "nonce": 5, "type": 2, "..." : "..." },
  "message": "Payment settled. Sign the transaction and POST to /api/broadcast."
}
```

### Step 4: Sign & broadcast

Sign the mint transaction locally, then submit it.

```javascript
import { ethers } from "ethers";

const PK = "YOUR_PRIVATE_KEY";
if (!/^0x[0-9a-fA-F]{64}$/.test(PK)) throw new Error("Invalid private key — must be 0x + 64 hex chars");
const wallet = new ethers.Wallet(PK);
const transaction = /* transaction object from Step 3 */;

const signedTransaction = await wallet.signTransaction(transaction);
console.log(JSON.stringify({ signedTransaction }));
```

```bash
curl -X POST https://budsbase.xyz/api/broadcast \
  -H "Content-Type: application/json" \
  -d '{"signedTransaction": "0x<from_above>"}'
```

Response:
```json
{
  "success": true,
  "tokenId": 9,
  "minter": "0x...",
  "txHash": "0x...",
  "minted": 2,
  "remaining": 18,
  "message": "Successfully minted Base Bud #9! You have minted 2 Base Buds. You can mint up to 18 more."
}
```

## Agent Behavior

- The user will provide their **wallet address** and **private key**. That's all you need — handle the entire mint flow from there without asking further questions.
- **Step 1** (challenge): use `curl`.
- **Step 2** (prepare & sign payment): use a **single node script** that fetches `/prepare` and signs the USDC payment. Do NOT split this into separate curl + node steps.
  - **ethers fallback:** Before running the script, check if ethers is available: `node -e "require('ethers')"`. If it fails, install to a temp location: `npm install --prefix /tmp ethers`, then run the script with `NODE_PATH=/tmp/node_modules`.
- **Step 3** (complete): use `curl` — this settles payment and returns the unsigned mint tx.
- **Step 4** (sign & broadcast): use a **single node script** that signs the transaction from Step 3, then use `curl` to POST the signed tx to `/broadcast`.
- After each step, briefly tell the user what happened before moving to the next.
- Handle errors gracefully — if a step fails, explain why and retry or stop.
- **Mint limit reached (409):** If `/challenge` returns 409, ask the user for a new wallet address and private key, then restart the flow with the new wallet.
- Never expose the user's private key in output or logs.
- Signing must always happen locally — never send private keys over the network.

## Error Codes

### `/challenge`

| Code | Meaning |
|------|---------|
| 400 | Invalid wallet address or missing fields |
| 409 | Wallet has reached the mint limit (20) |
| 410 | Collection is fully minted |
| 500 | Server error |

### `/prepare`

| Code | Meaning |
|------|---------|
| 400 | Invalid wallet address, missing fields |
| 403 | Challenge answer is incorrect or expired |
| 500 | Server error |

### `/complete`

All errors include a `code` field you can switch on:

| `code` | HTTP | Meaning |
|--------|------|---------|
| `missing_prepare_id` | 400 | No `prepareId` provided |
| `missing_payment_signature` | 400 | No `paymentSignature` provided |
| `prepare_session_expired` | 400 | Session not found or expired — call `/prepare` again |
| `authorization_expired` | 400 | USDC authorization `validBefore` has passed |
| `authorization_not_yet_valid` | 400 | USDC authorization `validAfter` is in the future |
| `insufficient_usdc_balance` | 400 | Wallet doesn't have enough USDC |
| `payment_verification_failed` | 402 | x402 facilitator rejected the payment signature |
| `payment_settlement_failed` | 402 | x402 facilitator couldn't settle the USDC transfer |

### `/broadcast`

| `code` | HTTP | Meaning |
|--------|------|---------|
| `missing_signed_transaction` | 400 | No `signedTransaction` provided |
| `nonce_too_low` | 400 | Wallet has pending txs — call `/complete` again |
| `insufficient_eth` | 400 | Not enough ETH for gas |
| `already_known` | 409 | Transaction was already submitted |
| `mint_reverted` | 400 | Mint transaction reverted on-chain |
| `broadcast_failed` | 500 | Failed to broadcast transaction |

## Notes

- **Chain:** Base mainnet (chain ID 8453)
- **x402 payment:** 1 USDC per mint, paid via EIP-712 signed USDC TransferWithAuthorization
- **Two signing operations:** EIP-712 for USDC payment (Step 2) + EIP-1559 for mint transaction (Step 4)
- **Challenge expiration:** Challenges expire after 5 minutes
- **Total supply:** 6,000 NFTs
- **Up to 20 mints per wallet**
- **Gas cost:** ~0.00025-0.000415 ETH per mint on Base

