Skill: zeroaddresss/usdc-escrow (version 1.0.0)

--- name: usdc-escrow description: "Trustless USDC escrow for agent-to-agent payments on Base. Create, release, dispute escrows via simple commands." metadata: openclaw: emoji: "🔐" requires: bins: [curl, jq] --- # USDC Escrow Skill ## Overview This skill provides trustless USDC escrow services for agent-to-agent payments on Base. It allows AI agents to create, manage, and resolve payment escrows using smart contracts. ## API All scripts point to `https://api.payclawback.xyz` by default. To use a different backend, set: - `ESCROW_API_URL` - Override API URL (optional) ## Available Commands ### Create an Escrow Creates a new escrow holding USDC for a beneficiary. ```bash ./scripts/create-escrow.sh <beneficiary_address> <amount_usdc> "<description>" <deadline_hours> ``` Example: `./scripts/create-escrow.sh 0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28 10 "Payment for data analysis" 48` ### List Escrows List all escrows, optionally filtered by state or depositor. ```bash ./scripts/list-escrows.sh [--state active|released|disputed|refunded|expired] [--depositor 0x...] ``` ### Get Escrow Details Get details of a specific escrow by ID. ```bash ./scripts/get-escrow.sh <escrow_id> ``` ### Release Escrow Release escrowed funds to the beneficiary. ```bash ./scripts/release-escrow.sh <escrow_id> ``` ### Dispute Escrow Open a dispute on an active escrow. ```bash ./scripts/dispute-escrow.sh <escrow_id> ``` ### Resolve Dispute Resolve a disputed escrow as arbiter. ```bash ./scripts/resolve-dispute.sh <escrow_id> <true|false> ``` - `true` = release funds to beneficiary - `false` = refund to depositor ### Claim Expired Escrow Reclaim funds from an expired escrow. ```bash ./scripts/claim-expired.sh <escrow_id> ``` ## Workflow Example 1. Agent A wants to pay Agent B for a service 2. Agent A creates an escrow: `./scripts/create-escrow.sh 0xAgentB 50 "Sentiment analysis job" 24` 3. Agent B performs the service 4. Agent A releases payment: `./scripts/release-escrow.sh 1` ## How It Works - USDC is locked in a [verified smart contract on Base](https://sepolia.basescan.org/address/0x2a27844f3775c3a446d32c06f4ebc3a02bb52e04) - The escrow has a deadline - funds return to depositor if expired - Either party can open a dispute for arbiter resolution - The AI arbiter agent resolves disputes impartially - All transactions are on-chain and verifiable ## API Reference See `references/api-docs.md` for complete API documentation.

path: references/api-docs.md
content: # USDC Escrow API Documentation

## Base URL

```
https://api.payclawback.xyz/api
```

## Endpoints

### Create Escrow

Creates a new USDC escrow on Base. The server wallet approves USDC spending and calls the smart contract to lock funds.

- **Method:** `POST`
- **Path:** `/api/escrows`
- **Auth:** None

**Request Body:**
```json
{
  "beneficiary": [REDACTED_SECRET],
  "amount": 10.5,
  "description": "Payment for data analysis",
  "deadline_hours": 48
}
```

| Field | Type | Description |
|-------|------|-------------|
| `beneficiary` | string | Ethereum address of the recipient |
| `amount` | number | USDC amount (e.g., 10.5 for 10.50 USDC) |
| `description` | string | Human-readable description of the escrow purpose |
| `deadline_hours` | number | Hours until the escrow expires and can be reclaimed |

**Response (201):**
```json
{
  "message": "Escrow created successfully",
  "escrowId": 1,
  "txHash": "0xabc123..."
}
```

**curl Example:**
```bash
curl -s -X POST "https://api.payclawback.xyz/api/escrows" \
  -H "Content-Type: application/json" \
  -d '{
    "beneficiary": [REDACTED_SECRET],
    "amount": 10,
    "description": "Payment for data analysis",
    "deadline_hours": 48
  }' | jq .
```

---

### List Escrows

Retrieve all escrows with optional filtering.

- **Method:** `GET`
- **Path:** `/api/escrows`
- **Auth:** Not required

**Query Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `state` | number | Filter by state: 0=Active, 1=Released, 2=Disputed, 3=Refunded, 4=Expired |
| `depositor` | string | Filter by depositor Ethereum address |
| `beneficiary` | string | Filter by beneficiary Ethereum address |

**Response (200):**
```json
{
  "escrows": [
    {
      "id": 1,
      "depositor": "0x...",
      "beneficiary": "0x...",
      "arbiter": "0x...",
      "amount": "10.5",
      "amountRaw": "10500000",
      "description": "Payment for data analysis",
      "deadline": "2025-01-17T12:00:00.000Z",
      "deadlineTimestamp": 1737115200,
      "state": 0,
      "stateName": "Active",
      "createdAt": "2025-01-15T12:00:00.000Z"
    }
  ],
  "count": 1
}
```

**curl Example:**
```bash
# List all escrows
curl -s "https://api.payclawback.xyz/api/escrows" | jq .

# Filter by state (active only)
curl -s "https://api.payclawback.xyz/api/escrows?state=0" | jq .

# Filter by depositor
curl -s "https://api.payclawback.xyz/api/escrows?depositor=0x742d..." | jq .
```

---

### Get Escrow

Retrieve details of a specific escrow by ID.

- **Method:** `GET`
- **Path:** `/api/escrows/:id`
- **Auth:** Not required

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `id` | number | The escrow ID |

**Response (200):**
```json
{
  "id": 1,
  "depositor": "0x...",
  "beneficiary": "0x...",
  "arbiter": "0x...",
  "amount": "10.5",
  "amountRaw": "10500000",
  "description": "Payment for data analysis",
  "deadline": "2025-01-17T12:00:00.000Z",
  "deadlineTimestamp": 1737115200,
  "state": 0,
  "stateName": "Active",
  "createdAt": "2025-01-15T12:00:00.000Z"
}
```

**curl Example:**
```bash
curl -s "https://api.payclawback.xyz/api/escrows/1" | jq .
```

---

### Release Escrow

Release escrowed USDC to the beneficiary. Only the depositor can release.

- **Method:** `POST`
- **Path:** `/api/escrows/:id/release`
- **Auth:** None

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `id` | number | The escrow ID to release |

**Response (200):**
```json
{
  "message": "Escrow released successfully",
  "txHash": "0xdef456..."
}
```

**curl Example:**
```bash
curl -s -X POST "https://api.payclawback.xyz/api/escrows/1/release" \
  -H "Content-Type: application/json" | jq .
```

---

### Dispute Escrow

Open a dispute on an active escrow. Either the depositor or beneficiary can dispute.

- **Method:** `POST`
- **Path:** `/api/escrows/:id/dispute`
- **Auth:** None

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `id` | number | The escrow ID to dispute |

**Response (200):**
```json
{
  "message": "Escrow disputed successfully",
  "txHash": "0xghi789..."
}
```

**curl Example:**
```bash
curl -s -X POST "https://api.payclawback.xyz/api/escrows/1/dispute" \
  -H "Content-Type: application/json" | jq .
```

---

### Resolve Dispute

Resolve a disputed escrow. Only the arbiter (server wallet) can resolve. Funds are sent either to the beneficiary or refunded to the depositor.

- **Method:** `POST`
- **Path:** `/api/escrows/:id/resolve`
- **Auth:** None

**Request Body:**
```json
{
  "release_to_beneficiary": true
}
```

| Field | Type | Description |
|-------|------|-------------|
| `release_to_beneficiary` | boolean | `true` to pay the beneficiary, `false` to refund the depositor |

**Response (200):**
```json
{
  "message": "Dispute resolved successfully",
  "txHash": "0xjkl012..."
}
```

**curl Example:**
```bash
curl -s -X POST "https://api.payclawback.xyz/api/escrows/1/resolve" \
  -H "Content-Type: application/json" \
  -d '{"release_to_beneficiary": true}' | jq .
```

---

### Claim Expired Escrow

Reclaim funds from an expired escrow. Only the depositor can claim after the deadline has passed.

- **Method:** `POST`
- **Path:** `/api/escrows/:id/claim-expired`
- **Auth:** None

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `id` | number | The escrow ID to claim |

**Response (200):**
```json
{
  "message": "Expired escrow claimed",
  "txHash": "0xmno345..."
}
```

**curl Example:**
```bash
curl -s -X POST "https://api.payclawback.xyz/api/escrows/1/claim-expired" \
  -H "Content-Type: application/json" | jq .
```

---

### Get Stats

Retrieve aggregate escrow statistics.

- **Method:** `GET`
- **Path:** `/api/stats`
- **Auth:** Not required

**Response (200):**
```json
{
  "total": 10,
  "active": 3,
  "released": 4,
  "disputed": 1,
  "refunded": 1,
  "expired": 1,
  "volume": "500.00"
}
```

**curl Example:**
```bash
curl -s "https://api.payclawback.xyz/api/stats" | jq .
```

---

## WebSocket

Real-time escrow events are available via WebSocket.

- **URL:** `ws://{ESCROW_API_URL}/ws`

**Event Format:**
```json
{
  "type": "EscrowCreated",
  "escrowId": 1,
  "timestamp": "2025-01-15T12:00:00.000Z",
  "data": {
    "depositor": "0x...",
    "beneficiary": "0x...",
    "amount": "10.5",
    "deadline": 1737115200
  },
  "txHash": "0xabc123..."
}
```

**Event Types:**
| Type | Description |
|------|-------------|
| `EscrowCreated` | A new escrow was created |
| `EscrowReleased` | Funds were released to the beneficiary |
| `EscrowDisputed` | A dispute was opened |
| `EscrowResolved` | A dispute was resolved by the arbiter |
| `EscrowExpired` | An expired escrow was claimed by the depositor |

---

## Escrow States

| Value | Name | Description |
|-------|------|-------------|
| 0 | Active | Escrow is active, funds are locked |
| 1 | Released | Funds released to beneficiary |
| 2 | Disputed | Dispute is open, awaiting arbiter resolution |
| 3 | Refunded | Funds refunded to depositor (via dispute resolution) |
| 4 | Expired | Deadline passed, depositor reclaimed funds |

---

## Error Responses

All errors follow a consistent format:

```json
{
  "error": "Description of what went wrong"
}
```

**Common HTTP Status Codes:**

| Code | Meaning |
|------|---------|
| 400 | Bad request - missing or invalid parameters |
| 500 | Internal server error - blockchain transaction failed |

---

## Network Details

- **Chain:** Base Sepolia
- **Chain ID:** 84532
- **Escrow Contract:** [[REDACTED_SECRET]](https://sepolia.basescan.org/address/0x2a27844f3775c3a446d32c06f4ebc3a02bb52e04) (verified)
- **USDC Contract:** [[REDACTED_SECRET]](https://sepolia.basescan.org/address/0x036CbD53842c5426634e7929541eC2318f3dCF7e)
- **USDC Decimals:** 6
- **RPC:** `https://sepolia.base.org`


path: scripts/claim-expired.sh
content: #!/bin/bash
# Claim funds from an expired escrow
set -e

API_URL="${ESCROW_API_URL:-https://api.payclawback.xyz}"

if [ $# -lt 1 ]; then
  echo "Usage: $0 <escrow_id>"
  exit 1
fi

ESCROW_ID="$1"

curl -s -X POST "${API_URL}/api/escrows/${ESCROW_ID}/claim-expired" \
  -H "Content-Type: application/json" | jq .


path: scripts/create-escrow.sh
content: #!/bin/bash
# Create a new USDC escrow
set -e

API_URL="${ESCROW_API_URL:-https://api.payclawback.xyz}"

if [ $# -lt 4 ]; then
  echo "Usage: $0 <beneficiary_address> <amount_usdc> <description> <deadline_hours>"
  echo "Example: $0 0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28 10 'Payment for service' 48"
  exit 1
fi

BENEFICIARY="$1"
AMOUNT="$2"
DESCRIPTION="$3"
DEADLINE_HOURS="$4"

curl -s -X POST "${API_URL}/api/escrows" \
  -H "Content-Type: application/json" \
  -d "{
    \"beneficiary\": \"${BENEFICIARY}\",
    \"amount\": ${AMOUNT},
    \"description\": \"${DESCRIPTION}\",
    \"deadline_hours\": ${DEADLINE_HOURS}
  }" | jq .


path: scripts/dispute-escrow.sh
content: #!/bin/bash
# Open a dispute on an escrow
set -e

API_URL="${ESCROW_API_URL:-https://api.payclawback.xyz}"

if [ $# -lt 1 ]; then
  echo "Usage: $0 <escrow_id>"
  exit 1
fi

ESCROW_ID="$1"

curl -s -X POST "${API_URL}/api/escrows/${ESCROW_ID}/dispute" \
  -H "Content-Type: application/json" | jq .


path: scripts/get-escrow.sh
content: #!/bin/bash
# Get details of a specific escrow
set -e

API_URL="${ESCROW_API_URL:-https://api.payclawback.xyz}"

if [ $# -lt 1 ]; then
  echo "Usage: $0 <escrow_id>"
  exit 1
fi

ESCROW_ID="$1"

curl -s "${API_URL}/api/escrows/${ESCROW_ID}" | jq .


path: scripts/list-escrows.sh
content: #!/bin/bash
# List escrows with optional filters
set -e

API_URL="${ESCROW_API_URL:-https://api.payclawback.xyz}"

QUERY=""
while [[ $# -gt 0 ]]; do
  case $1 in
    --state)
      STATE_MAP=("active=0" "released=1" "disputed=2" "refunded=3" "expired=4")
      for mapping in "${STATE_MAP[@]}"; do
        key="${mapping%%=*}"
        val="${mapping##*=}"
        if [ "$2" = "$key" ]; then
          QUERY="${QUERY:+$QUERY&}state=$val"
          break
        fi
      done
      shift 2
      ;;
    --depositor)
      QUERY="${QUERY:+$QUERY&}depositor=$2"
      shift 2
      ;;
    *)
      echo "Usage: $0 [--state active|released|disputed|refunded|expired] [--depositor 0x...]"
      exit 1
      ;;
  esac
done

curl -s "${API_URL}/api/escrows${QUERY:+?$QUERY}" | jq .


path: scripts/release-escrow.sh
content: #!/bin/bash
# Release escrowed USDC to beneficiary
set -e

API_URL="${ESCROW_API_URL:-https://api.payclawback.xyz}"

if [ $# -lt 1 ]; then
  echo "Usage: $0 <escrow_id>"
  exit 1
fi

ESCROW_ID="$1"

curl -s -X POST "${API_URL}/api/escrows/${ESCROW_ID}/release" \
  -H "Content-Type: application/json" | jq .


path: scripts/resolve-dispute.sh
content: #!/bin/bash
# Resolve a disputed escrow
set -e

API_URL="${ESCROW_API_URL:-https://api.payclawback.xyz}"

if [ $# -lt 2 ]; then
  echo "Usage: $0 <escrow_id> <true|false>"
  echo "  true  = release funds to beneficiary"
  echo "  false = refund to depositor"
  exit 1
fi

ESCROW_ID="$1"
RELEASE_TO_BENEFICIARY="$2"

curl -s -X POST "${API_URL}/api/escrows/${ESCROW_ID}/resolve" \
  -H "Content-Type: application/json" \
  -d "{\"release_to_beneficiary\": ${RELEASE_TO_BENEFICIARY}}" | jq .


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