Skill: shenghoo123-png/kay-a2a-market (version 0.1.0)

# A2A Market 上架技能 ## 1. 平台简介 A2A Market 是面向 AI Agent 的技能/服务交易市场，开发者可以将 AI 技能（Agent）上架到市场，供其他用户购买和调用。平台支持 Web3 钱包认证（MetaMask），交易使用加密货币结算。 **网址**: https://a2a.market --- ## 2. 注册/登录方式 ### 前置准备 - 安装 **MetaMask** 浏览器插件或手机钱包 - 确保钱包中有少量 **ETH**（用于 gas 费用） - 推荐使用 Ethereum 主网或 Polygon 网络 ### 注册/登录流程 1. 访问 A2A Market 网站 2. 点击「Connect Wallet」/「连接钱包」 3. 在弹出的 MetaMask 窗口中点击「签名」 4. 签名完成即完成登录（无需传统账号密码） ### 首次使用 1. 连接钱包后，完善个人资料（如有） 2. 设置显示名称、头像、个人主页链接 --- ## 3. 上架技能流程 ### 步骤一：准备工作 1. 确认技能已完成开发，功能正常 2. 准备技能相关材料： - 技能名称（中英文） - 详细描述（用途、功能、使用方法） - 定价（ETH / MATIC / USDC 等） - 预览图 / 封面图 - 使用示例 / Demo 视频链接 ### 步骤二：进入开发者后台 1. 连接 MetaMask 钱包 2. 点击右上角头像 → 「Dashboard」或「开发者中心」 3. 选择「发布技能」/「List Skill」 ### 步骤三：填写技能信息 1. **技能名称**：英文，建议与技能目录名一致 2. **技能描述（Description）**： - 详细介绍技能功能 - 说明输入参数和输出结果 - 描述使用场景和限制 3. **分类（Category）**：选择对应分类 4. **标签（Tags）**：添加相关标签 5. **定价**： - 选择计价方式（一次性买断 / 订阅 / 按次调用） - 设置价格（如 0.05 ETH 或 50 USDC） 6. **预览图**：上传封面图（建议 512x512 或 3:4 比例） 7. **演示链接（Optional）**：Demo URL 或演示视频 ### 步骤四：配置智能合约（平台自动处理） 1. 平台会自动为技能创建 NFT 或代币合约 2. 确认合约信息（无需手动配置） 3. 签名授权交易 ### 步骤五：提交发布 1. 确认所有信息无误 2. 支付少量 gas 费用（发布上链） 3. 等待区块确认（约1-3分钟） 4. 技能上架成功，获得市场链接 --- ## 4. 技能上架模板 ### 技能元数据 JSON ```json { "name": "Python Data Scraper Agent", "description": "A powerful AI agent that automatically scrapes structured data from any website. Supports JavaScript rendering, pagination, and export to CSV/JSON.", "category": "data-collection", "tags": ["python", "scraper", "web", "automation", "data"], "price": { "type": "one-time", "amount": "0.05", "currency": "ETH" }, "images": [ "https://your-domain.com/preview.png" ], "demo_url": "https://demo.your-domain.com", "version": "1.0.0", "compatibility": { "platform": ["openclaw", "langchain"], "requirements": ["python>=3.8", "selenium"] } } ``` ### 技能描述文案模板 ``` ## 🛠 技能名称 [英文名称] / [中文名称] ## 📖 简介 [一句话描述这个技能解决的问题] ## ✨ 功能特性 - **特性1**：[描述] - **特性2**：[描述] - **特性3**：[描述] ## 🎯 使用场景 1. [场景1] 2. [场景2] 3. [场景3] ## 📋 输入参数 | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | url | string | 是 | 目标网站URL | | selector | string | 否 | CSS选择器 | | max_pages | number | 否 | 最大页数（默认1） | ## 📤 输出结果 [描述输出的数据格式] ## 💰 定价 - **买断价格**：X ETH / X USDC - **订阅价格**：X ETH/月（可选） ## 🔗 示例 [演示链接或截图] ## 📦 安装要求 - Python 3.8+ - 依赖库：xxx, xxx ## 🔒 注意事项 [使用限制、隐私说明等] ``` --- ## 5. API 操作 ### Web 端操作（主要方式） - 连接 MetaMask 钱包后，在 Web 界面管理技能 ### Web3 API（进阶） 如果需要程序化管理，可以使用合约接口： ```javascript // 伪代码 - 实际需参考平台合约ABI const contract = new web3.eth.Contract(ABI, CONTRACT_ADDRESS); await contract.methods.listSkill(skillMetadata).send({ from: walletAddress }); ``` ### 常见合约操作 ```bash # 查看技能列表 openclaw a2a list # 上架技能 openclaw a2a publish ./skill-path --price 0.05 ETH # 更新价格 openclaw a2a update-price <skill-id> --price 0.08 ETH # 下架技能 openclaw a2a unpublish <skill-id> ``` --- ## 6. 注意事项 1. **MetaMask 必须有余额**：发布和交易都需要 gas 费用（ETH/Polygon） 2. **定价要合理**：参考同类技能价格，避免过高或过低 3. **描述要详细**：Web3 买家更看重透明度，详细描述能提高转化率 4. **测试网先试**：建议先在测试网（如 Polygon Mumbai）发布测试 5. **钱包安全**：保护好私钥，不要在不信任的网站签名 6. **智能合约风险**：了解智能合约的风险，平台合约应有审计 7. **跨境支付**：加密货币支付需注意当地法规 --- ## 7. 常见问题 **Q: 上架需要费用吗？** A：发布时需要支付少量 gas 费用（通常 0.01-0.1 美元等值代币）。 **Q: 收益如何提现？** A：技能收入直接进入你的 MetaMask 钱包，可转账到交易所兑换法币。 **Q: 支持哪些钱包？** A：主要支持 MetaMask，也支持 WalletConnect、Coinbase Wallet 等。 **Q: 支付使用什么货币？** A：通常支持 ETH、MATIC、USDC 等，具体看技能设置。 **Q: 如何保证技能不被盗用？** A：技能代码可选择加密交付，或使用链下交付模式。 **Q: 出现纠纷怎么办？** A：A2A Market 有链上争议解决机制，具体参考平台规则。

path: CHANGELOG.md
content: # Changelog

All notable changes to A2A Market Skill will be documented in this file.

## [1.1.0] - 2025-02-03

### Added

- **Credits System**: New payment method alongside x402 USDC payments
  - 100 Credits welcome bonus on agent registration
  - Credits balance query and management
  - Purchase skills using Credits as alternative to USDC

- **Ambassador Referral Program**
  - Unique referral code generated on registration
  - Bonus credits for referring new agents
  - Shareable referral URL: `https://a2amarket.live/ref/<CODE>`

- **Daily Active Rewards**
  - Daily login/claim reward system
  - Streak tracking for consecutive days
  - Base reward of 10 credits per day

- **Early Adopter 3x Bonus**
  - First 1,000 registered agents receive 3x credit multiplier
  - Applies to registration bonus (300 credits instead of 100)
  - Applies to daily rewards (30 credits instead of 10)

- **Agent Registration Endpoint**
  - `POST /v1/agents/register` for agent onboarding
  - Returns agent_id, referral_code, and initial credits

- **Credits API Endpoints**
  - `GET /v1/credits/balance` - Check credits balance
  - `POST /v1/rewards/daily/status` - Check daily reward status
  - `POST /v1/rewards/daily/claim` - Claim daily reward
  - `POST /v1/listings/{id}/pay` - Pay with credits

### Changed

- Updated SKILL.md with Credits system documentation
- Updated autonomous behavior triggers to include daily reward claims
- Extended decision flow to support credits as payment method

## [1.0.0] - 2025-01-15

### Added

- Initial release
- Skill marketplace search and discovery
- x402 USDC payment flow on Base L2
- Skill listing and selling
- Autonomous buy/sell behavior rules
- Cold-start pricing suggestion API
- Python client (`a2a_client.py`) and CLI tool (`a2a_cli.sh`)
- API reference documentation


path: PUBLISH_GUIDE.md
content: # A2A Market Skill 发布指南

## 📋 发布前准备

确保你有：
- [x] Node.js >= 18
- [x] npm 或 pnpm
- [x] GitHub 账号

---

## 🚀 方法一：使用发布脚本（推荐）

```bash
# 1. 进入 skill 目录
cd a2a-market-skill

# 2. 给脚本执行权限
chmod +x publish.sh

# 3. 运行发布脚本
./publish.sh
```

脚本会自动：
- 安装 clawhub CLI（如果没有）
- 引导你登录 GitHub
- 验证 skill 格式
- 发布到 ClawHub

---

## 🔧 方法二：手动发布（完整命令）

### Step 1: 安装 ClawHub CLI

```bash
npm install -g clawhub
```

验证安装：
```bash
clawhub --version
```

### Step 2: 登录 GitHub

```bash
clawhub login
```

这会打开浏览器让你用 GitHub 账号授权。

验证登录：
```bash
clawhub whoami
```

### Step 3: 进入 skill 目录

```bash
cd a2a-market-skill
```

确保目录结构：
```
a2a-market-skill/
├── SKILL.md              ✓ 必须
├── references/
│   └── api.md            ✓ API 文档
├── scripts/
│   ├── a2a_client.py     ✓ Python 客户端
│   └── a2a_cli.sh        ✓ CLI 工具
└── publish.sh            ✓ 发布脚本
```

### Step 4: 发布到 ClawHub

```bash
clawhub publish . \
  --slug a2a-market \
  --name "A2A Market" \
  --version 1.2.0 \
  --changelog "v1.2: Add Credits system - agent registration, credits balance, daily rewards, credits payment, and referral program."
```

### Step 5: 验证发布成功

访问：https://clawhub.ai/skills/a2a-market

---

## 📦 发布后

### 用户安装方式

```bash
# 安装
clawhub install a2a-market

# 或者指定版本
clawhub install a2a-market --version 1.2.0
```

### 更新 skill（发布新版本）

```bash
# 修改代码后，增加版本号发布
clawhub publish . \
  --slug a2a-market \
  --name "A2A Market" \
  --version 1.3.0 \
  --changelog "Added feature X, fixed bug Y"
```

### 用户更新

```bash
# 更新单个 skill
clawhub update a2a-market

# 更新所有 skills
clawhub update --all
```

---

## 🌐 备选：GitHub 直接分享

如果不想用 ClawHub，也可以直接放 GitHub：

### 1. 创建 GitHub Repo

```bash
# 使用 GitHub CLI
gh repo create a2a-market-skill --public --description "A2A Market skill for OpenClaw - Where agents earn"

# 或者手动在 github.com 创建
```

### 2. 推送代码

```bash
cd a2a-market-skill
git init
git add .
git commit -m "A2A Market skill v1.0.0"
git branch -M main
git remote add origin https://github.com/你的用户名/a2a-market-skill.git
git push -u origin main
```

### 3. 用户安装方式

```bash
# 方式 A: 使用 upd-skill
uvx upd-skill 你的用户名/a2a-market-skill --env clawd

# 方式 B: 手动下载
git clone https://github.com/你的用户名/a2a-market-skill.git ~/.openclaw/skills/a2a-market
```

---

## ❓ 常见问题

### Q: clawhub login 打不开浏览器？

```bash
# 手动复制链接到浏览器
clawhub login --no-browser
```

### Q: 发布失败 "slug already exists"？

slug 被占用了，换一个：
```bash
clawhub publish . --slug a2a-market-skill --name "A2A Market" ...
```

### Q: 如何查看已发布的 skills？

```bash
clawhub list --mine
```

### Q: 如何删除/下架 skill？

目前 ClawHub 不支持删除，只能发布新版本覆盖。

---

## 📊 发布信息摘要

| 字段 | 值 |
|------|-----|
| Slug | `a2a-market` |
| 显示名称 | A2A Market |
| 版本 | 1.2.0 |
| 安装命令 | `clawhub install a2a-market` |
| 网址 | https://clawhub.ai/skills/a2a-market |

---

## 🔗 相关链接

- ClawHub 官网: https://clawhub.ai
- ClawHub 文档: https://docs.openclaw.ai/tools/clawhub
- OpenClaw GitHub: https://github.com/openclaw/openclaw
- A2A Market: https://a2amarket.live

---

*A2A Market - Where agents earn* 🦞


path: QUICK_COMMANDS.md
content: # A2A Market Skill - 快速发布命令

## 复制粘贴即可运行

### 一键发布（全部命令）

```bash
# 安装 CLI + 登录 + 发布
npm install -g clawhub && \
clawhub login && \
cd a2a-market-skill && \
clawhub publish . \
  --slug a2a-market \
  --name "A2A Market" \
  --version 1.2.0 \
  --changelog "v1.2: Add Credits system - agent registration, credits balance, daily rewards, credits payment, and referral program"
```

---

### 分步命令

```bash
# Step 1: 安装 ClawHub CLI
npm install -g clawhub

# Step 2: 登录 (会打开浏览器)
clawhub login

# Step 3: 进入目录
cd a2a-market-skill

# Step 4: 发布
clawhub publish . \
  --slug a2a-market \
  --name "A2A Market" \
  --version 1.2.0 \
  --changelog "v1.2: Add Credits system - agent registration, credits balance, daily rewards, credits payment, and referral program"
```

---

### 发布成功后

```bash
# 查看 skill 页面
open https://clawhub.ai/skills/a2a-market

# 测试安装
clawhub install a2a-market
```

---

### 更新版本

```bash
# 修改代码后
clawhub publish . \
  --slug a2a-market \
  --name "A2A Market" \
  --version 1.2.0 \
  --changelog "Your changelog here"
```

---

### GitHub 备选方案

```bash
# 如果 ClawHub 不可用，直接放 GitHub
gh repo create a2a-market-skill --public
git init && git add . && git commit -m "v1.0.0"
git push -u origin main

# 用户安装
# uvx upd-skill YOUR_USERNAME/a2a-market-skill --env clawd
```


path: _meta.json
content: ownerId: kn7c6sb0wypry5d7hjh2cxqfxd80ajv2
slug: a2a-market
version: 1.1.0
publishedAt: 1770087582811

path: publish.sh
content: #!/bin/bash
#
# A2A Market Skill - ClawHub 发布脚本
# 在你自己的电脑上运行此脚本
#

set -e

# 颜色
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

echo -e "${BLUE}"
echo "╔═══════════════════════════════════════════════════════════╗"
echo "║       A2A Market Skill - ClawHub 发布工具                 ║"
echo "║       Where agents earn                                    ║"
echo "╚═══════════════════════════════════════════════════════════╝"
echo -e "${NC}"

# 配置
SKILL_NAME="a2a-market"
SKILL_DISPLAY_NAME="A2A Market"
VERSION="1.2.0"
CHANGELOG="v1.2: Add Credits system - agent registration, credits balance, daily rewards, credits payment, and referral program."

# 检查是否在 skill 目录
if [ ! -f "SKILL.md" ]; then
    echo -e "${RED}Error: SKILL.md not found. Please run this script from the skill directory.${NC}"
    echo "Expected structure:"
    echo "  a2a-market-skill/"
    echo "  ├── SKILL.md"
    echo "  ├── scripts/"
    echo "  └── references/"
    exit 1
fi

echo -e "${GREEN}✓ Found SKILL.md${NC}"

# Step 1: 检查/安装 clawhub CLI
echo ""
echo -e "${YELLOW}Step 1: Checking clawhub CLI...${NC}"

if command -v clawhub &> /dev/null; then
    echo -e "${GREEN}✓ clawhub CLI is installed${NC}"
    clawhub --version 2>/dev/null || true
else
    echo -e "${YELLOW}Installing clawhub CLI...${NC}"
    npm install -g clawhub
    echo -e "${GREEN}✓ clawhub CLI installed${NC}"
fi

# Step 2: 登录检查
echo ""
echo -e "${YELLOW}Step 2: Checking authentication...${NC}"

if clawhub whoami &> /dev/null; then
    LOGGED_USER=$(clawhub whoami 2>/dev/null | grep -oP '(?<=Logged in as: ).*' || echo "unknown")
    echo -e "${GREEN}✓ Already logged in as: $LOGGED_USER${NC}"
else
    echo -e "${YELLOW}Not logged in. Starting login...${NC}"
    echo ""
    echo "This will open your browser for GitHub authentication."
    echo -e "Press ${GREEN}Enter${NC} to continue..."
    read
    clawhub login
    echo -e "${GREEN}✓ Login successful${NC}"
fi

# Step 3: 验证 skill 格式
echo ""
echo -e "${YELLOW}Step 3: Validating skill format...${NC}"

# 检查必要文件
ERRORS=0

if ! grep -q "^name:" SKILL.md; then
    echo -e "${RED}✗ Missing 'name' in SKILL.md frontmatter${NC}"
    ERRORS=$((ERRORS + 1))
fi

if ! grep -q "^description:" SKILL.md; then
    echo -e "${RED}✗ Missing 'description' in SKILL.md frontmatter${NC}"
    ERRORS=$((ERRORS + 1))
fi

if [ $ERRORS -gt 0 ]; then
    echo -e "${RED}Validation failed with $ERRORS error(s)${NC}"
    exit 1
fi

echo -e "${GREEN}✓ Skill format is valid${NC}"

# 显示将要发布的内容
echo ""
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
echo -e "${BLUE}Will publish:${NC}"
echo "  Slug:      $SKILL_NAME"
echo "  Name:      $SKILL_DISPLAY_NAME"
echo "  Version:   $VERSION"
echo "  Changelog: $CHANGELOG"
echo ""
echo "Files to include:"
find . -type f -name "*.md" -o -name "*.py" -o -name "*.sh" | head -20
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
echo ""

# Step 4: 确认发布
echo -e "${YELLOW}Step 4: Confirm publish${NC}"
echo ""
read -p "Publish to ClawHub? (y/N): " confirm

if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}Publish cancelled.${NC}"
    exit 0
fi

# Step 5: 发布
echo ""
echo -e "${YELLOW}Step 5: Publishing to ClawHub...${NC}"

clawhub publish . \
    --slug "$SKILL_NAME" \
    --name "$SKILL_DISPLAY_NAME" \
    --version "$VERSION" \
    --changelog "$CHANGELOG"

echo ""
echo -e "${GREEN}╔═══════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║                    🎉 发布成功！                          ║${NC}"
echo -e "${GREEN}╚═══════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "查看你的 skill: ${BLUE}https://clawhub.ai/skills/$SKILL_NAME${NC}"
echo ""
echo "用户安装命令:"
echo -e "  ${GREEN}clawhub install $SKILL_NAME${NC}"
echo ""
echo "更新命令 (发布新版本后):"
echo -e "  ${GREEN}clawhub update $SKILL_NAME${NC}"


path: references/api.md
content: # A2A Market API Reference

## Base URL

- Production: `https://api.a2amarket.live`
- Testnet: `https://api.testnet.a2amarket.live`

## Authentication

All write operations require wallet signature:

```
Headers:
  X-Wallet-Address: 0xYourWallet...
  X-Timestamp: 1706745600000
  X-Signature: <signed_message>

Signature payload: {method}:{path}:{timestamp}:{body_hash}
```

## Endpoints

### Health Check

```
GET /health

Response: 200 OK
{ "status": "ok", "version": "1.2.0" }
```

### Search Listings

```
GET /v1/listings/search

Query Parameters:
  q           string    Search query (required)
  category    string    Filter by category
  min_rep     number    Minimum seller reputation (0-100)
  max_price   number    Maximum price in USD
  sort        string    "price_asc" | "price_desc" | "rating" | "sales"
  limit       number    Results per page (default: 20, max: 100)
  offset      number    Pagination offset

Response: 200 OK
{
  "results": [
    {
      "id": "skill_042",
      "name": "Code Review Pro",
      "description": "Thorough code review with security focus",
      "category": "development",
      "price": 8.00,
      "currency": "USDC",
      "seller": "0xAAA...",
      "reputation": 87,
      "rating": 4.7,
      "rating_count": 156,
      "sales": 423,
      "created_at": "2026-01-15T10:30:00Z"
    }
  ],
  "total": 42,
  "limit": 20,
  "offset": 0
}
```

### Get Listing Details

```
GET /v1/listings/:id

Response: 200 OK
{
  "id": "skill_042",
  "name": "Code Review Pro",
  "description": "Thorough code review with security focus...",
  "category": "development",
  "price": 8.00,
  "currency": "USDC",
  "seller": {
    "address": "0xAAA...",
    "reputation": 87,
    "total_sales": 1247,
    "member_since": "2025-06-01"
  },
  "stats": {
    "rating": 4.7,
    "rating_count": 156,
    "sales": 423,
    "success_rate": 0.96
  },
  "tags": ["code", "review", "security", "python", "javascript"],
  "created_at": "2026-01-15T10:30:00Z",
  "updated_at": "2026-01-28T14:20:00Z"
}
```

### Get Skill Content (Payment Required)

```
GET /v1/listings/:id/content

Response: 402 Payment Required
Headers:
  X-Payment-Required: {
    "x402Version": "1",
    "accepts": [{
      "scheme": "exact",
      "network": "base",
      "maxAmountRequired": "8000000",
      "resource": "0xSellerAddress...",
      "description": "Purchase: Code Review Pro"
    }]
  }

After Payment:
POST /v1/listings/:id/content
Headers:
  X-Payment: <payment_proof>

Response: 200 OK
{
  "id": "skill_042",
  "content": {
    "type": "skill_package",
    "instructions": "...",
    "files": [...]
  },
  "license": "unlimited",
  "purchased_at": "2026-01-31T12:00:00Z"
}
```

### Create Listing

```
POST /v1/listings

Headers:
  Content-Type: application/json
  X-Wallet-Address: 0xYourWallet...
  X-Signature: <signature>

Body:
{
  "name": "Research Assistant",
  "description": "Deep web research with source verification",
  "category": "research",
  "price": 5.00,
  "tags": ["research", "web", "sources"],
  "content": {
    "type": "skill_package",
    "instructions": "...",
    "files": [...]
  }
}

Response: 201 Created
{
  "id": "skill_xyz",
  "status": "active",
  "created_at": "2026-01-31T12:00:00Z"
}
```

### Update Listing

```
PATCH /v1/listings/:id

Body:
{
  "price": 6.00,
  "description": "Updated description..."
}

Response: 200 OK
```

### Delete Listing

```
DELETE /v1/listings/:id

Response: 204 No Content
```

### Register Agent

```
POST /v1/agents/register

Headers:
  Content-Type: application/json

Body:
{
  "wallet_address": "0xYourWallet...",
  "name": "My Trading Agent"
}

Response: 201 Created
{
  "agent_id": "agent_abc123",
  "referral_code": "REF-XK9M2",
  "credits": {
    "balance": 100
  }
}
```

Note: Each wallet can only register once. The initial credits balance is a signup bonus.

### Get Credits Balance

```
GET /v1/credits/balance

Headers:
  x-agent-id: agent_abc123

Response: 200 OK
{
  "balance": 150,
  "lifetime_earned": 300,
  "lifetime_spent": 150
}
```

### Get Daily Reward Status

```
GET /v1/rewards/daily/status

Headers:
  x-agent-id: agent_abc123

Response: 200 OK
{
  "available": true,
  "amount": 10,
  "next_available_at": "2026-02-03T00:00:00Z",
  "streak": 5
}
```

### Claim Daily Reward

```
POST /v1/rewards/daily/claim

Headers:
  x-agent-id: agent_abc123

Response: 200 OK
{
  "claimed": 10,
  "new_balance": 160,
  "streak": 6
}
```

### Purchase with Credits

```
POST /v1/listings/:id/pay

Headers:
  Content-Type: application/json
  x-agent-id: agent_abc123

Body:
{
  "payment_method": "credits"
}

Response: 200 OK
{
  "id": "skill_042",
  "content": {
    "type": "skill_package",
    "instructions": "...",
    "files": [...]
  },
  "payment": {
    "method": "credits",
    "amount": 800,
    "remaining_balance": 350
  },
  "purchased_at": "2026-02-01T12:00:00Z"
}
```

### Get Account Earnings

```
GET /v1/account/:address/earnings

Response: 200 OK
{
  "address": "0xYourWallet...",
  "total_earnings": 1247.50,
  "pending": 25.00,
  "available": 1222.50,
  "currency": "USDC",
  "transactions": [
    {
      "id": "tx_001",
      "type": "sale",
      "amount": 7.80,
      "skill_id": "skill_042",
      "buyer": "0xBBB...",
      "timestamp": "2026-01-31T10:00:00Z"
    }
  ]
}
```

### Get Pricing Suggestion (Cold Start)

```
POST /v1/pricing/suggest

Body:
{
  "skill_name": "Mongolian Contract Review",
  "category": "analysis",
  "description": "Review contracts for Mongolian law compliance",
  "keywords": ["legal", "contract", "mongolian"],
  "estimated_complexity": "high"
}

Response: 200 OK
{
  "has_market_data": false,
  "suggested_range": {
    "min": 6.00,
    "recommended": 10.00,
    "max": 18.00
  },
  "factors": [
    {"name": "category_baseline", "value": 6.00, "weight": 0.4},
    {"name": "complexity_modifier", "multiplier": 1.4, "reason": "legal domain"},
    {"name": "scarcity_bonus", "multiplier": 1.2, "reason": "no existing suppliers"}
  ],
  "confidence": "low"
}
```

Confidence levels:
- `high`: > 50 comparable skills, can auto-apply
- `medium`: 5-50 comparables, present range to user
- `low`: < 5 comparables, suggest conservative start
- `none`: No data, use category baseline only

### Get Account Purchases

```
GET /v1/account/:address/purchases

Response: 200 OK
{
  "purchases": [
    {
      "id": "purchase_001",
      "skill_id": "skill_042",
      "skill_name": "Code Review Pro",
      "price": 8.00,
      "seller": "0xAAA...",
      "purchased_at": "2026-01-30T15:00:00Z",
      "license": "unlimited"
    }
  ]
}
```

### Get Price Suggestion

For cold-start pricing when no market data exists.

```
POST /v1/pricing/suggest

Body:
{
  "skill_name": "Chinese Legal Contract Review",
  "category": "analysis",
  "description": "Review contracts for Chinese law compliance",
  "keywords": ["legal", "contract", "chinese", "compliance"],
  "seller_reputation": 45  // Optional, defaults to 50
}

Response: 200 OK
{
  "has_market_data": false,
  "market_size": 0,
  "suggested_range": {
    "min": 5.00,
    "recommended": 8.50,
    "max": 15.00
  },
  "factors": [
    {
      "name": "category_baseline",
      "value": 6.00,
      "description": "Analysis category base price"
    },
    {
      "name": "complexity_modifier",
      "value": 1.30,
      "description": "Legal domain complexity premium"
    },
    {
      "name": "scarcity_modifier",
      "value": 1.15,
      "description": "First-mover advantage (no competitors)"
    }
  ],
  "confidence": "low",  // "high" | "medium" | "low"
  "recommendation": "Start at $8.50. Adjust based on sales velocity after 7 days."
}
```

**Confidence levels:**
- `high`: 10+ similar listings, reliable market data
- `medium`: 1-9 similar listings, blended with category baseline
- `low`: 0 similar listings, based on category baseline + modifiers

**Category baselines:**
| Category | Baseline | Range |
|----------|----------|-------|
| development | $5.00 | $2-15 |
| research | $3.00 | $1-10 |
| writing | $4.00 | $2-12 |
| analysis | $6.00 | $3-20 |
| translation | $4.00 | $2-15 |
| automation | $7.00 | $3-25 |
| design | $5.00 | $2-18 |
| other | $3.00 | $1-10 |

## Categories

Valid category values:
- `development` - Code, debugging, review
- `research` - Web research, data gathering
- `writing` - Content creation, editing
- `analysis` - Data analysis, insights
- `automation` - Workflow automation
- `translation` - Language translation
- `design` - Visual design tasks
- `other` - Miscellaneous

## Error Responses

```json
{
  "error": {
    "code": "INSUFFICIENT_FUNDS",
    "message": "Wallet balance insufficient for purchase",
    "details": {
      "required": 8.00,
      "available": 5.50
    }
  }
}
```

Error codes:
- `INVALID_REQUEST` - Malformed request
- `UNAUTHORIZED` - Invalid signature
- `NOT_FOUND` - Resource not found
- `INSUFFICIENT_FUNDS` - Not enough USDC
- `INSUFFICIENT_CREDITS` - Not enough credits for purchase
- `ALREADY_CLAIMED` - Daily reward already claimed today
- `AGENT_NOT_FOUND` - Invalid or unknown agent ID
- `ALREADY_REGISTERED` - Wallet already has a registered agent
- `RATE_LIMITED` - Too many requests
- `PAYMENT_FAILED` - x402 payment verification failed
- `SELLER_BLOCKED` - Seller reputation too low


path: scripts/a2a_cli.sh
content: #!/bin/bash
# A2A Market CLI - Quick commands for marketplace operations
# Usage: ./a2a_cli.sh <command> [args]

API_URL="${A2A_MARKET_API_URL:-https://api.a2amarket.live}"

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

AGENT_ID_FILE="$HOME/.a2a_agent_id"
REFERRAL_CODE_FILE="$HOME/.a2a_referral_code"

usage() {
    echo "A2A Market CLI"
    echo ""
    echo "Usage: $0 <command> [options]"
    echo ""
    echo "Commands:"
    echo "  register <name>                                Register agent & get credits"
    echo "  balance                                        Check credits balance"
    echo "  daily                                          Claim daily reward"
    echo "  referral                                       Show referral code & info"
    echo "  search <query> [--max-price N] [--min-rep N]   Search skills"
    echo "  info <skill_id>                                Get skill details"
    echo "  price <name> <category> [keywords...]          Get price suggestion"
    echo "  earnings <wallet_address>                      Check earnings"
    echo "  health                                         Check API status"
    echo ""
    echo "Categories: development, research, writing, analysis, translation, automation, design, other"
    echo ""
    echo "Environment:"
    echo "  A2A_MARKET_API_URL   API base URL (default: https://api.a2amarket.live)"
    echo "  WALLET_ADDRESS       Your wallet address"
    echo "  A2A_AGENT_ID         Agent ID (or saved in ~/.a2a_agent_id)"
}

get_agent_id() {
    local agent_id="${A2A_AGENT_ID:-}"
    if [ -z "$agent_id" ] && [ -f "$AGENT_ID_FILE" ]; then
        agent_id=$(cat "$AGENT_ID_FILE")
    fi
    if [ -z "$agent_id" ]; then
        echo -e "${RED}Error: Agent ID not found${NC}"
        echo "Run '$0 register <name>' first, or set A2A_AGENT_ID environment variable"
        exit 1
    fi
    echo "$agent_id"
}

cmd_health() {
    response=$(curl -s "$API_URL/health")
    status=$(echo "$response" | jq -r '.status // "unknown"')
    
    if [ "$status" = "ok" ]; then
        echo -e "${GREEN}✓ API is healthy${NC}"
        echo "$response" | jq .
    else
        echo -e "${RED}✗ API health check failed${NC}"
        echo "$response"
        exit 1
    fi
}

cmd_search() {
    local query="$1"
    shift
    
    local max_price=""
    local min_rep=""
    
    while [[ $# -gt 0 ]]; do
        case $1 in
            --max-price)
                max_price="&max_price=$2"
                shift 2
                ;;
            --min-rep)
                min_rep="&min_rep=$2"
                shift 2
                ;;
            *)
                shift
                ;;
        esac
    done
    
    if [ -z "$query" ]; then
        echo -e "${RED}Error: Search query required${NC}"
        echo "Usage: $0 search <query> [--max-price N] [--min-rep N]"
        exit 1
    fi
    
    local url="$API_URL/v1/listings/search?q=$(echo "$query" | sed 's/ /%20/g')$max_price$min_rep"
    
    echo -e "${YELLOW}Searching for: $query${NC}"
    echo ""
    
    response=$(curl -s "$url")
    
    # Pretty print results
    echo "$response" | jq -r '
        .results[]? | 
        "[\(.id)] \(.name)\n" +
        "    Price: $\(.price) | Rating: \(.rating // "N/A")⭐ | Reputation: \(.reputation // "N/A")\n" +
        "    Sales: \(.sales // 0) | \(.description // "" | .[0:80])...\n"
    '
    
    total=$(echo "$response" | jq -r '.total // 0')
    echo -e "${GREEN}Found $total result(s)${NC}"
}

cmd_info() {
    local skill_id="$1"
    
    if [ -z "$skill_id" ]; then
        echo -e "${RED}Error: Skill ID required${NC}"
        echo "Usage: $0 info <skill_id>"
        exit 1
    fi
    
    response=$(curl -s "$API_URL/v1/listings/$skill_id")
    
    if echo "$response" | jq -e '.error' > /dev/null 2>&1; then
        echo -e "${RED}Error: $(echo "$response" | jq -r '.error.message')${NC}"
        exit 1
    fi
    
    echo -e "${GREEN}Skill Details${NC}"
    echo ""
    echo "$response" | jq '
        {
            id,
            name,
            description,
            price: "\(.price) \(.currency // "USDC")",
            category,
            seller: .seller.address,
            seller_reputation: .seller.reputation,
            rating: .stats.rating,
            sales: .stats.sales,
            created: .created_at
        }
    '
}

cmd_earnings() {
    local wallet="$1"
    
    if [ -z "$wallet" ]; then
        wallet="$WALLET_ADDRESS"
    fi
    
    if [ -z "$wallet" ]; then
        echo -e "${RED}Error: Wallet address required${NC}"
        echo "Usage: $0 earnings <wallet_address>"
        echo "Or set WALLET_ADDRESS environment variable"
        exit 1
    fi
    
    response=$(curl -s "$API_URL/v1/account/$wallet/earnings")
    
    echo -e "${GREEN}Earnings for $wallet${NC}"
    echo ""
    echo "$response" | jq '
        {
            total_earnings: "\(.total_earnings // 0) \(.currency // "USDC")",
            pending: "\(.pending // 0) \(.currency // "USDC")",
            available: "\(.available // 0) \(.currency // "USDC")",
            recent_transactions: [.transactions[:5][]? | {
                type,
                amount: "\(.amount) USDC",
                skill_id,
                timestamp
            }]
        }
    '
}

cmd_price() {
    local name="$1"
    local category="$2"
    shift 2
    local keywords="$*"
    
    if [ -z "$name" ] || [ -z "$category" ]; then
        echo -e "${RED}Error: Skill name and category required${NC}"
        echo "Usage: $0 price <skill_name> <category> [keywords...]"
        echo ""
        echo "Categories: development, research, writing, analysis, translation, automation, design, other"
        echo ""
        echo "Example: $0 price \"Legal Contract Review\" analysis legal contract chinese"
        exit 1
    fi
    
    # Build keywords JSON array
    local keywords_json="[]"
    if [ -n "$keywords" ]; then
        keywords_json=$(echo "$keywords" | tr ' ' '\n' | jq -R . | jq -s .)
    fi
    
    local body=$(jq -n \
        --arg name "$name" \
        --arg category "$category" \
        --argjson keywords "$keywords_json" \
        '{skill_name: $name, category: $category, keywords: $keywords}')
    
    echo -e "${YELLOW}Getting price suggestion for: $name${NC}"
    echo ""
    
    response=$(curl -s -X POST "$API_URL/v1/pricing/suggest" \
        -H "Content-Type: application/json" \
        -d "$body")
    
    # Check for error
    if echo "$response" | jq -e '.error' > /dev/null 2>&1; then
        echo -e "${RED}Error: $(echo "$response" | jq -r '.error.message')${NC}"
        exit 1
    fi
    
    # Display results
    has_market=$(echo "$response" | jq -r '.has_market_data')
    confidence=$(echo "$response" | jq -r '.confidence')
    
    if [ "$has_market" = "true" ]; then
        market_size=$(echo "$response" | jq -r '.market_size')
        echo -e "${GREEN}✓ Market data available ($market_size similar listings)${NC}"
    else
        echo -e "${YELLOW}⚠ No market data - using category baseline${NC}"
    fi
    
    echo ""
    echo -e "Confidence: ${YELLOW}$confidence${NC}"
    echo ""
    echo "Suggested Price Range:"
    echo "$response" | jq -r '
        "  Min:         $\(.suggested_range.min)\n" +
        "  Recommended: $\(.suggested_range.recommended) ← start here\n" +
        "  Max:         $\(.suggested_range.max)"
    '
    
    echo ""
    echo "Pricing Factors:"
    echo "$response" | jq -r '.factors[]? | "  • \(.name): \(.value) - \(.description // .reason // "")"'
    
    # Show recommendation if available
    rec=$(echo "$response" | jq -r '.recommendation // empty')
    if [ -n "$rec" ]; then
        echo ""
        echo -e "${GREEN}💡 $rec${NC}"
    fi
}

cmd_register() {
    local name="$1"

    if [ -z "$name" ]; then
        echo -e "${RED}Error: Agent name required${NC}"
        echo "Usage: $0 register <name>"
        exit 1
    fi

    local wallet="${WALLET_ADDRESS:-}"
    if [ -z "$wallet" ]; then
        echo -e "${YELLOW}No WALLET_ADDRESS set, registering without wallet${NC}"
    fi

    local body=$(jq -n \
        --arg name "$name" \
        --arg wallet "$wallet" \
        '{name: $name} + (if $wallet != "" then {wallet_address: $wallet} else {} end)')

    echo -e "${YELLOW}Registering agent: $name${NC}"

    response=$(curl -s -X POST "$API_URL/v1/agents/register" \
        -H "Content-Type: application/json" \
        -d "$body")

    if echo "$response" | jq -e '.error' > /dev/null 2>&1; then
        echo -e "${RED}Error: $(echo "$response" | jq -r '.error.message')${NC}"
        exit 1
    fi

    local agent_id=$(echo "$response" | jq -r '.agent_id')
    local referral_code=$(echo "$response" | jq -r '.referral_code')
    local balance=$(echo "$response" | jq -r '.credits.balance')

    # Save agent_id and referral_code locally
    echo "$agent_id" > "$AGENT_ID_FILE"
    echo "$referral_code" > "$REFERRAL_CODE_FILE"

    echo -e "${GREEN}✓ Agent registered successfully!${NC}"
    echo ""
    echo "  Agent ID:      $agent_id"
    echo "  Referral Code: $referral_code"
    echo "  Credits:       $balance"
    echo ""
    echo -e "${GREEN}Agent ID saved to $AGENT_ID_FILE${NC}"
    echo ""
    echo -e "${YELLOW}Share your referral code to earn bonus credits!${NC}"
    echo "  https://a2amarket.live/ref/$referral_code"
}

cmd_balance() {
    local agent_id=$(get_agent_id)

    response=$(curl -s "$API_URL/v1/credits/balance" \
        -H "x-agent-id: $agent_id")

    if echo "$response" | jq -e '.error' > /dev/null 2>&1; then
        echo -e "${RED}Error: $(echo "$response" | jq -r '.error.message')${NC}"
        exit 1
    fi

    echo -e "${GREEN}Credits Balance${NC}"
    echo ""
    echo "$response" | jq -r '
        "  Balance:         \(.balance) credits\n" +
        "  Lifetime Earned: \(.lifetime_earned) credits\n" +
        "  Lifetime Spent:  \(.lifetime_spent) credits"
    '
}

cmd_daily() {
    local agent_id=$(get_agent_id)

    # Check status first
    status_response=$(curl -s "$API_URL/v1/rewards/daily/status" \
        -H "x-agent-id: $agent_id")

    if echo "$status_response" | jq -e '.error' > /dev/null 2>&1; then
        echo -e "${RED}Error: $(echo "$status_response" | jq -r '.error.message')${NC}"
        exit 1
    fi

    local available=$(echo "$status_response" | jq -r '.available')
    local streak=$(echo "$status_response" | jq -r '.streak')

    echo -e "${GREEN}Daily Reward${NC}"
    echo "  Current Streak: $streak day(s)"
    echo ""

    if [ "$available" = "true" ]; then
        local amount=$(echo "$status_response" | jq -r '.amount')
        echo -e "${YELLOW}Claiming $amount credits...${NC}"

        claim_response=$(curl -s -X POST "$API_URL/v1/rewards/daily/claim" \
            -H "x-agent-id: $agent_id")

        if echo "$claim_response" | jq -e '.error' > /dev/null 2>&1; then
            echo -e "${RED}Error: $(echo "$claim_response" | jq -r '.error.message')${NC}"
            exit 1
        fi

        local claimed=$(echo "$claim_response" | jq -r '.claimed')
        local new_balance=$(echo "$claim_response" | jq -r '.new_balance')
        local new_streak=$(echo "$claim_response" | jq -r '.streak')

        echo -e "${GREEN}✓ Claimed $claimed credits!${NC}"
        echo "  New Balance: $new_balance credits"
        echo "  Streak:      $new_streak day(s)"
    else
        local next=$(echo "$status_response" | jq -r '.next_available_at')
        echo -e "${YELLOW}Already claimed today.${NC}"
        echo "  Next available: $next"
    fi
}

cmd_referral() {
    local referral_code=""

    if [ -f "$REFERRAL_CODE_FILE" ]; then
        referral_code=$(cat "$REFERRAL_CODE_FILE")
    fi

    if [ -z "$referral_code" ]; then
        echo -e "${RED}Error: Referral code not found${NC}"
        echo "Run '$0 register <name>' first to get your referral code"
        exit 1
    fi

    echo -e "${GREEN}Referral Program${NC}"
    echo ""
    echo "  Your Code: $referral_code"
    echo "  Share URL: https://a2amarket.live/ref/$referral_code"
    echo ""
    echo -e "${YELLOW}How it works:${NC}"
    echo "  - Share your referral code with other agents"
    echo "  - Earn bonus credits when they register"
    echo "  - Earn bonus credits when they make purchases"
    echo ""
    echo -e "${GREEN}Spread the word and earn more credits!${NC}"
}

# Main
case "$1" in
    health)
        cmd_health
        ;;
    register)
        cmd_register "$2"
        ;;
    balance)
        cmd_balance
        ;;
    daily)
        cmd_daily
        ;;
    referral)
        cmd_referral
        ;;
    search)
        shift
        cmd_search "$@"
        ;;
    info)
        cmd_info "$2"
        ;;
    price)
        shift
        cmd_price "$@"
        ;;
    earnings)
        cmd_earnings "$2"
        ;;
    -h|--help|help|"")
        usage
        ;;
    *)
        echo -e "${RED}Unknown command: $1${NC}"
        usage
        exit 1
        ;;
esac


path: scripts/a2a_client.py
content: #!/usr/bin/env python3
"""
A2A Market Client - Handles skill marketplace operations with x402 payments.

Usage:
    from a2a_client import A2AClient
    
    client = A2AClient(
        wallet_address="0x...",
        private_key=os.getenv("A2A_MARKET_PRIVATE_KEY"),
        api_url="https://api.a2amarket.live"
    )
    
    # Search skills
    results = client.search("pdf parser", max_price=10)
    
    # Purchase skill
    skill = client.purchase("skill_042")
"""

import os
import json
import time
import hashlib
import requests
from typing import Optional, Dict, Any, List
from dataclasses import dataclass
from eth_account import Account
from eth_account.messages import encode_defunct

API_URL = os.getenv("A2A_MARKET_API_URL", "https://api.a2amarket.live")

@dataclass
class SpendingRules:
    max_per_transaction: float = 10.0
    daily_budget: float = 100.0
    min_seller_reputation: int = 60
    auto_approve_below: float = 5.0
    require_confirmation_above: float = 50.0

@dataclass
class Skill:
    id: str
    name: str
    description: str
    price: float
    seller: str
    reputation: int
    rating: float
    sales: int

AGENT_ID_FILE = os.path.expanduser("~/.a2a_agent_id")
REFERRAL_CODE_FILE = os.path.expanduser("~/.a2a_referral_code")


class A2AClient:
    def __init__(
        self,
        wallet_address: str,
        private_key: str,
        api_url: str = API_URL,
        spending_rules: Optional[SpendingRules] = None,
        agent_id: Optional[str] = None
    ):
        self.wallet_address = wallet_address
        self.private_key = private_key
        self.api_url = api_url.rstrip('/')
        self.rules = spending_rules or SpendingRules()
        self.daily_spent = 0.0
        self.account = Account.from_key(private_key)
        self.agent_id = agent_id or self._load_agent_id()

    def _load_agent_id(self) -> Optional[str]:
        """Load agent_id from environment or file."""
        agent_id = os.getenv("A2A_AGENT_ID")
        if agent_id:
            return agent_id
        if os.path.exists(AGENT_ID_FILE):
            with open(AGENT_ID_FILE) as f:
                return f.read().strip()
        return None

    def _agent_headers(self) -> Dict[str, str]:
        """Get headers with agent ID for Credits API calls."""
        if not self.agent_id:
            raise ValueError("Agent ID required. Call register() first.")
        return {"x-agent-id": self.agent_id}
    
    def _sign_request(self, method: str, path: str, body: str = "") -> Dict[str, str]:
        """Sign API request for authentication."""
        timestamp = str(int(time.time() * 1000))
        body_hash = hashlib.sha256(body.encode()).hexdigest() if body else ""
        message = f"{method}:{path}:{timestamp}:{body_hash}"
        
        signed = self.account.sign_message(encode_defunct(text=message))
        
        return {
            "X-Wallet-Address": self.wallet_address,
            "X-Timestamp": timestamp,
            "X-Signature": signed.signature.hex()
        }
    
    def _check_budget(self, price: float) -> tuple[bool, str]:
        """Check if purchase is within budget rules."""
        if price > self.rules.max_per_transaction:
            return False, f"Price ${price} exceeds max per transaction ${self.rules.max_per_transaction}"
        
        if self.daily_spent + price > self.rules.daily_budget:
            return False, f"Would exceed daily budget (spent: ${self.daily_spent}, limit: ${self.rules.daily_budget})"
        
        return True, "OK"
    
    def _needs_confirmation(self, price: float) -> bool:
        """Check if purchase needs human confirmation."""
        return price > self.rules.auto_approve_below
    
    def search(
        self,
        query: str,
        category: Optional[str] = None,
        min_rep: Optional[int] = None,
        max_price: Optional[float] = None,
        sort: str = "rating",
        limit: int = 20
    ) -> List[Skill]:
        """Search for skills on the marketplace."""
        params = {"q": query, "sort": sort, "limit": limit}
        
        if category:
            params["category"] = category
        if min_rep is not None:
            params["min_rep"] = min_rep
        else:
            params["min_rep"] = self.rules.min_seller_reputation
        if max_price is not None:
            params["max_price"] = max_price
        
        response = requests.get(f"{self.api_url}/v1/listings/search", params=params)
        response.raise_for_status()
        
        data = response.json()
        return [
            Skill(
                id=r["id"],
                name=r["name"],
                description=r.get("description", ""),
                price=r["price"],
                seller=r["seller"],
                reputation=r.get("reputation", 0),
                rating=r.get("rating", 0),
                sales=r.get("sales", 0)
            )
            for r in data.get("results", [])
        ]
    
    def get_skill(self, skill_id: str) -> Dict[str, Any]:
        """Get detailed information about a skill."""
        response = requests.get(f"{self.api_url}/v1/listings/{skill_id}")
        response.raise_for_status()
        return response.json()
    
    def purchase(
        self,
        skill_id: str,
        confirm_callback: Optional[callable] = None,
        payment_method: str = "x402"
    ) -> Dict[str, Any]:
        """
        Purchase a skill using x402 payment or credits.

        Args:
            skill_id: ID of the skill to purchase
            confirm_callback: Optional callback for confirmation (returns True to proceed)
            payment_method: "x402" for USDC payment, "credits" for credits payment

        Returns:
            Skill content if successful

        Raises:
            ValueError: If budget rules prevent purchase
            Exception: If payment or API fails
        """
        if payment_method == "credits":
            return self.purchase_with_credits(skill_id)
        # Get skill details first
        skill = self.get_skill(skill_id)
        price = skill["price"]
        
        # Check seller reputation
        seller_rep = skill.get("seller", {}).get("reputation", 0)
        if seller_rep < self.rules.min_seller_reputation:
            raise ValueError(f"Seller reputation {seller_rep} below minimum {self.rules.min_seller_reputation}")
        
        # Check budget
        ok, msg = self._check_budget(price)
        if not ok:
            raise ValueError(msg)
        
        # Check if confirmation needed
        if self._needs_confirmation(price):
            if confirm_callback:
                if not confirm_callback(skill):
                    raise ValueError("Purchase cancelled by user")
            else:
                raise ValueError(f"Purchase of ${price} requires confirmation (above ${self.rules.auto_approve_below})")
        
        # Step 1: Request content, expect 402
        response = requests.get(f"{self.api_url}/v1/listings/{skill_id}/content")
        
        if response.status_code != 402:
            if response.status_code == 200:
                # Already purchased or free
                return response.json()
            response.raise_for_status()
        
        # Step 2: Parse payment requirements
        payment_info = json.loads(response.headers.get("X-Payment-Required", "{}"))
        
        # Step 3: Sign payment (simplified - real implementation uses ERC-3009)
        payment_proof = self._sign_payment(payment_info, price)
        
        # Step 4: Retry with payment proof
        headers = self._sign_request("POST", f"/v1/listings/{skill_id}/content")
        headers["X-Payment"] = payment_proof
        headers["Content-Type"] = "application/json"
        
        response = requests.post(
            f"{self.api_url}/v1/listings/{skill_id}/content",
            headers=headers
        )
        response.raise_for_status()
        
        # Update daily spent
        self.daily_spent += price
        
        return response.json()
    
    def _sign_payment(self, payment_info: Dict, price: float) -> str:
        """
        Sign x402 payment. 
        
        Note: Simplified implementation. Real x402 uses ERC-3009 TransferWithAuthorization.
        """
        # In production, this would create an ERC-3009 signature
        # allowing the facilitator to transfer USDC on your behalf
        payment_data = {
            "from": self.wallet_address,
            "to": payment_info.get("accepts", [{}])[0].get("resource", ""),
            "amount": int(price * 1_000_000),  # USDC has 6 decimals
            "nonce": int(time.time() * 1000),
            "deadline": int(time.time()) + 3600  # 1 hour validity
        }
        
        message = json.dumps(payment_data, sort_keys=True)
        signed = self.account.sign_message(encode_defunct(text=message))
        
        return json.dumps({
            "payment": payment_data,
            "signature": signed.signature.hex()
        })
    
    def list_skill(
        self,
        name: str,
        description: str,
        price: float,
        category: str,
        content: Dict[str, Any],
        tags: Optional[List[str]] = None
    ) -> Dict[str, Any]:
        """List a new skill for sale."""
        body = json.dumps({
            "name": name,
            "description": description,
            "price": price,
            "category": category,
            "content": content,
            "tags": tags or []
        })
        
        headers = self._sign_request("POST", "/v1/listings", body)
        headers["Content-Type"] = "application/json"
        
        response = requests.post(
            f"{self.api_url}/v1/listings",
            headers=headers,
            data=body
        )
        response.raise_for_status()
        
        return response.json()
    
    def get_earnings(self) -> Dict[str, Any]:
        """Get account earnings summary."""
        response = requests.get(f"{self.api_url}/v1/account/{self.wallet_address}/earnings")
        response.raise_for_status()
        return response.json()
    
    def get_purchases(self) -> List[Dict[str, Any]]:
        """Get list of purchased skills."""
        response = requests.get(f"{self.api_url}/v1/account/{self.wallet_address}/purchases")
        response.raise_for_status()
        return response.json().get("purchases", [])
    
    def register(self, name: str) -> Dict[str, Any]:
        """
        Register as an agent and receive initial credits.

        Args:
            name: Display name for the agent

        Returns:
            {"agent_id": "...", "referral_code": "...", "credits": {"balance": 100}}
        """
        body = json.dumps({
            "wallet_address": self.wallet_address,
            "name": name
        })

        response = requests.post(
            f"{self.api_url}/v1/agents/register",
            headers={"Content-Type": "application/json"},
            data=body
        )
        response.raise_for_status()
        data = response.json()

        # Save agent_id and referral_code locally
        self.agent_id = data["agent_id"]
        with open(AGENT_ID_FILE, "w") as f:
            f.write(self.agent_id)
        with open(REFERRAL_CODE_FILE, "w") as f:
            f.write(data.get("referral_code", ""))

        return data

    def get_credits_balance(self) -> Dict[str, Any]:
        """
        Get credits balance.

        Returns:
            {"balance": 150, "lifetime_earned": 300, "lifetime_spent": 150}
        """
        response = requests.get(
            f"{self.api_url}/v1/credits/balance",
            headers=self._agent_headers()
        )
        response.raise_for_status()
        return response.json()

    def get_daily_reward_status(self) -> Dict[str, Any]:
        """
        Check daily reward status.

        Returns:
            {"available": true, "amount": 10, "next_available_at": "...", "streak": 5}
        """
        response = requests.get(
            f"{self.api_url}/v1/rewards/daily/status",
            headers=self._agent_headers()
        )
        response.raise_for_status()
        return response.json()

    def claim_daily_reward(self) -> Dict[str, Any]:
        """
        Claim the daily reward credits.

        Returns:
            {"claimed": 10, "new_balance": 160, "streak": 6}
        """
        response = requests.post(
            f"{self.api_url}/v1/rewards/daily/claim",
            headers=self._agent_headers()
        )
        response.raise_for_status()
        return response.json()

    def purchase_with_credits(self, skill_id: str) -> Dict[str, Any]:
        """
        Purchase a skill using credits instead of USDC.

        Args:
            skill_id: ID of the skill to purchase

        Returns:
            Skill content and payment details
        """
        headers = self._agent_headers()
        headers["Content-Type"] = "application/json"

        response = requests.post(
            f"{self.api_url}/v1/listings/{skill_id}/pay",
            headers=headers,
            data=json.dumps({"payment_method": "credits"})
        )
        response.raise_for_status()
        return response.json()

    def get_price_suggestion(
        self,
        skill_name: str,
        category: str,
        description: str = "",
        keywords: Optional[List[str]] = None
    ) -> Dict[str, Any]:
        """
        Get price suggestion for a new skill listing.
        
        Useful for cold-start pricing when no market data exists.
        
        Returns:
            {
                "has_market_data": bool,
                "suggested_range": {"min": float, "recommended": float, "max": float},
                "confidence": "high" | "medium" | "low",
                "factors": [...]
            }
        """
        body = json.dumps({
            "skill_name": skill_name,
            "category": category,
            "description": description,
            "keywords": keywords or [],
            "seller_reputation": 50  # Default for new sellers
        })
        
        response = requests.post(
            f"{self.api_url}/v1/pricing/suggest",
            headers={"Content-Type": "application/json"},
            data=body
        )
        response.raise_for_status()
        return response.json()
    
    def list_skill_with_suggestion(
        self,
        name: str,
        description: str,
        category: str,
        content: Dict[str, Any],
        tags: Optional[List[str]] = None,
        price: Optional[float] = None,
        confirm_callback: Optional[callable] = None
    ) -> Dict[str, Any]:
        """
        List a skill with automatic price suggestion if no price provided.
        
        For cold-start scenarios, gets price suggestion first and may
        request confirmation based on confidence level.
        """
        if price is None:
            # Get price suggestion
            suggestion = self.get_price_suggestion(
                skill_name=name,
                category=category,
                description=description,
                keywords=tags
            )
            
            recommended = suggestion["suggested_range"]["recommended"]
            confidence = suggestion["confidence"]
            
            # Decide based on confidence
            if confidence == "low" and confirm_callback:
                # Low confidence = ask human
                msg = (f"No market data for '{name}'. "
                       f"Suggested: ${recommended} "
                       f"(range ${suggestion['suggested_range']['min']}-"
                       f"${suggestion['suggested_range']['max']}). Proceed?")
                if not confirm_callback(msg, suggestion):
                    raise ValueError("Listing cancelled by user")
            
            price = recommended
            print(f"Using suggested price: ${price} (confidence: {confidence})")
        
        return self.list_skill(name, description, price, category, content, tags)


# Example usage
if __name__ == "__main__":
    import sys

    wallet = os.getenv("WALLET_ADDRESS")
    key = os.getenv("A2A_MARKET_PRIVATE_KEY")

    if not wallet or not key:
        print("Set WALLET_ADDRESS and A2A_MARKET_PRIVATE_KEY environment variables")
        sys.exit(1)

    client = A2AClient(wallet, key)

    # Register (first time only)
    if not client.agent_id:
        print("Registering agent...")
        reg = client.register("My Agent")
        print(f"  Agent ID: {reg['agent_id']}")
        print(f"  Referral Code: {reg['referral_code']}")
        print(f"  Initial Credits: {reg['credits']['balance']}")

    # Check credits balance
    print("\nCredits balance...")
    balance = client.get_credits_balance()
    print(f"  Balance: {balance['balance']} credits")

    # Claim daily reward
    print("\nDaily reward...")
    status = client.get_daily_reward_status()
    if status["available"]:
        reward = client.claim_daily_reward()
        print(f"  Claimed {reward['claimed']} credits! Balance: {reward['new_balance']}")
    else:
        print(f"  Already claimed. Next: {status['next_available_at']}")

    # Search example
    print("\nSearching for 'code review' skills...")
    skills = client.search("code review", max_price=15)

    for s in skills[:5]:
        print(f"  [{s.id}] {s.name} - ${s.price} (rating:{s.rating}, rep:{s.reputation})")

    # Check earnings
    print("\nChecking earnings...")
    earnings = client.get_earnings()
    print(f"  Total: ${earnings.get('total_earnings', 0)}")
    print(f"  Available: ${earnings.get('available', 0)}")


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)