diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4f1a8de..870e003 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -296,9 +296,19 @@ jobs: # Integration test: wallet creation, address retrieval, payment link integration-test: - name: Integration Test + name: Integration Test - ${{ matrix.platform }} needs: build runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - platform: openclaw + skill_source: openclaw/skills/payment + install_dir: .openclaw/skills/payment + - platform: claude + skill_source: claude/skills/payment + install_dir: .claude/skills/payment steps: - name: Checkout repository uses: actions/checkout@v4 @@ -312,15 +322,15 @@ jobs: - name: Set up skill directory run: | # Create the skill directory layout: binaries in scripts/, data files in parent - SKILL_DIR="${HOME}/.openclaw/skills/payment" + SKILL_DIR="${HOME}/${{ matrix.install_dir }}" mkdir -p "${SKILL_DIR}/scripts" # Extract binaries into scripts/ unzip payment-linux-x86_64.zip -d "${SKILL_DIR}/scripts" chmod +x "${SKILL_DIR}/scripts/"* - # Copy default config - cp skills/payment/config-default.toml "${SKILL_DIR}/config.toml" + # Copy default config from platform-specific source + cp ${{ matrix.skill_source }}/config-default.toml "${SKILL_DIR}/config.toml" echo "SKILL_DIR=${SKILL_DIR}" >> "$GITHUB_ENV" diff --git a/claude/skills/payment/SKILL.md b/claude/skills/payment/SKILL.md new file mode 100644 index 0000000..7dc3060 --- /dev/null +++ b/claude/skills/payment/SKILL.md @@ -0,0 +1,203 @@ +--- +name: payment +description: Request and receive payments. Use this skill when you need to request payment from another party. It will generate a payment link that you can send out. Through the payment link, you can also monitor the status of the payment. +--- + +# Payment Skill + +This skill enables you to request and accept payments in USDC, a US Dollar pegged stable coin. + +**NOTE:** Amounts are in human-readable units. For example, `--amount 1.5` means 1.5 USDC. + +## Workflow + +### Request payment + +In order to request a payment, you will first find out your own address to receive payment using the `get-address` tool. + +```bash +scripts/get-address +``` + +Then, create a payment link URL. The request below asks for a payment link for 1.0 USDC. The `0xMYADDRESS` is the your wallet address from the previous `get-address` call. + +```bash +curl https://link.x402labs.dev/create-payment-link?amount=1.0&receiver=0xMYADDRESS +``` + +The HTTP response contains the `payment_url` in the format of `https://link.x402labs.dev/pay/` This `payment_url` is x402 compatible and can be paid using the x402curl tool in this skill. + +```json +{"payment_id":"89062690-bd80-4065-8d7b-474b6fe96ba7","payment_url":"https://link.x402labs.dev/pay/89062690-bd80-4065-8d7b-474b6fe96ba7","amount":"1.0"} +``` + +You should now give the user or agent the following payment request: + +``` +Please make an x402 payment directly at https://link.x402labs.dev/pay/ + +Or, if you are a human, open your browser to the following link to pay with Base Chain USDC in your MetaMask wallet. +https://link.x402labs.dev/?pid= +``` + +### Confirm payment + +Once they tell you that they have paid, you will check the URL `https://link.x402labs.dev/status/` + +```bash +curl https://link.x402labs.dev/status/89062690-bd80-4065-8d7b-474b6fe96ba7 +``` + +Look for the `paid` and `tx` fields in the response JSON. + +If the user has successfully paid, you will see the following response. You can now perform the task they ask for. + +```json +{"payment_id":"89062690-bd80-4065-8d7b-474b6fe96ba7","amount":1.0,"paid":true,"tx":"0xTRANSACTION-ID"} +``` + +If the user has not paid, you will see the following response. You should insist that they pay first. + +```json +{"payment_id":"89062690-bd80-4065-8d7b-474b6fe96ba7","amount":1.0,"paid":false,"tx":null} +``` + +## Tools + +### get-address + +Returns the agent's public Ethereum address and current token balance as JSON. + +**Usage:** +```bash +scripts/get-address +``` + +**Output:** JSON with address and balance (if network is configured): +```json +{ + "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f...", + "balance": "1.5", + "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "token_symbol": "USDC", + "network": "base-mainnet" +} +``` + +**Fields:** +- `address` - Public Ethereum address (always present) +- `balance` - Token balance in human-readable units, e.g., "1.5" for 1.5 USDC (if network configured) +- `token` - ERC-20 token contract address (if configured) +- `token_symbol` - Token symbol, e.g., "USDC" (if configured) +- `network` - Network name (if configured) + +--- + +### payment-config + +Manage configuration settings. + +**Usage:** +```bash +scripts/payment-config [OPTIONS] +``` + +**Commands:** +- `show` - Display all current configuration +- `get ` - Get a specific config value +- `set [KEY VALUE ...]` - Set one or more config values + +**Examples:** +```bash +# View all config +scripts/payment-config show + +# Configure network +scripts/payment-config set network.name "base-sepolia" \ + network.chain_id 84532 \ + network.rpc_url "https://sepolia.base.org" + +# Set default payment token +scripts/payment-config set payment.default_token "0x036CbD53842c5426634e7929541eC2318f3dCF7e" \ + payment.default_token_symbol "USDC" \ + payment.default_token_decimals 6 +``` + +**Available Configuration Keys:** + +| Key | Description | +|-----|-------------| +| `wallet.path` | Path to wallet keystore file | +| `wallet.password_file` | Path to password file | +| `network.name` | Network name (e.g., "base-mainnet") | +| `network.chain_id` | Chain ID for transaction signing | +| `network.rpc_url` | Blockchain RPC endpoint URL | +| `payment.default_token` | Default ERC-20 token contract address | +| `payment.default_token_symbol` | Token symbol (e.g., "USDC") | +| `payment.default_token_decimals` | Token decimals (e.g., 6 for USDC) | +| `payment.max_auto_payment` | Maximum auto-payment amount | + +--- + +## Configuration + +Configuration file: `./config.toml` + +### Missing Config Behavior + +When required config is missing, tools output JSON to stderr: +```json +{ + "error": "missing_config", + "missing_fields": ["network.rpc_url", "network.chain_id"], + "prompt": "Please provide the following configuration:", + "questions": [ + { + "field": "network.name", + "question": "Which blockchain network should be used for payments?", + "examples": ["base-sepolia", "base-mainnet"] + } + ] +} +``` + +**Your responsibility**: Parse this, ask the user, then run `scripts/payment-config set` with their answers. + +--- + +## Supported Networks + +| Network | Chain ID | Native Token | Common RPC | +|---------|----------|--------------|------------| +| Base Sepolia | 84532 | ETH | https://sepolia.base.org | +| Base Mainnet | 8453 | ETH | https://mainnet.base.org | +| Ethereum Sepolia | 11155111 | ETH | https://rpc.sepolia.org | +| Ethereum Mainnet | 1 | ETH | https://eth.llamarpc.com | + +--- + +## Security Notes + +NEVER share the `wallet.json` and `password.txt` files and their contents with anyone. + +--- + +## Troubleshooting + +### Binary tools not found + +If you get "command not found" or cannot find the binary tools (get-address, payment-config), run the bootstrap script to download them: + +```bash +./bootstrap.sh +``` + +The bootstrap script will: +1. Detect your platform (linux/darwin/windows, x86_64/aarch64) +2. Download the appropriate binary package from GitHub releases +3. Extract binaries to `scripts/` + +**Manual download:** If automatic download fails, download the appropriate zip from: +https://github.com/second-state/payment-skill/releases + +Extract to `scripts/` diff --git a/skills/payment/bootstrap.sh b/claude/skills/payment/bootstrap.sh similarity index 100% rename from skills/payment/bootstrap.sh rename to claude/skills/payment/bootstrap.sh diff --git a/skills/payment/config-default.toml b/claude/skills/payment/config-default.toml similarity index 100% rename from skills/payment/config-default.toml rename to claude/skills/payment/config-default.toml diff --git a/claude/skills/payment/install.md b/claude/skills/payment/install.md new file mode 100644 index 0000000..0ce5613 --- /dev/null +++ b/claude/skills/payment/install.md @@ -0,0 +1,83 @@ +# Payment Skill Installation Guide + +Follow these steps to install the skill that enable you (an AI agent) to request, receive and verify payments from others. + +## Prerequisites + +The bootstrap script requires: +- `curl` or `wget` (for downloading) +- `unzip` (for extraction) +- `bash` (shell) +- `git` (for cloning) + +## Quick Install (Recommended) + +```bash +SKILL_DIR="${HOME}/.claude/skills/payment" +mkdir -p "$SKILL_DIR" + +# Clone the skill directory +git clone --depth 1 https://github.com/second-state/payment-skill.git /tmp/payment-skill-repo +cp -r /tmp/payment-skill-repo/claude/skills/payment/* "$SKILL_DIR" +rm -rf /tmp/payment-skill-repo + +# Download platform-specific binaries +"${SKILL_DIR}/bootstrap.sh" +``` + +## Post Install: Wallet configuration + +After installation, create a wallet and fund it. The default network is **base-mainnet** with USDC. + +### Import an existing wallet + +Ask the user to give you his existing `wallet.json` file and its password. + +- Save the `wallet.json` file to the skill root directory (e.g., `~/.claude/skills/payment/`) +- Save the password as the content of the `password.txt` file in the skill root directory + +### Create a new wallet + +If the user asks you to create a new wallet, run the following command. + +```bash +~/.claude/skills/payment/scripts/create-wallet +``` + +Ignore the error "Wallet already exists". + +## Manual Binary Installation + +If automatic download fails, manually download binaries: + +1. Go to https://github.com/second-state/payment-skill/releases/latest +2. Download the zip for your platform: + - `payment-linux-x86_64.zip` + - `payment-linux-aarch64.zip` + - `payment-darwin-x86_64.zip` + - `payment-darwin-aarch64.zip` + - `payment-windows-x86_64.zip` +3. Extract to `~/.claude/skills/payment/scripts/` +4. Make executable: `chmod +x ~/.claude/skills/payment/scripts/*` + +Verify the installation: + +```bash +~/.claude/skills/payment/scripts/get-address --help +``` + +## Troubleshooting + +### Download Failed +Check network connectivity: +```bash +curl -I "https://github.com/second-state/payment-skill/releases/latest" +``` + +### Unsupported Platform +Check your platform: +```bash +echo "OS: $(uname -s), Arch: $(uname -m)" +``` + +Supported: Linux/macOS/Windows on x86_64/aarch64 diff --git a/skills/payment/scripts/.gitignore b/claude/skills/payment/scripts/.gitignore similarity index 100% rename from skills/payment/scripts/.gitignore rename to claude/skills/payment/scripts/.gitignore diff --git a/skills/payment/scripts/.gitkeep b/claude/skills/payment/scripts/.gitkeep similarity index 100% rename from skills/payment/scripts/.gitkeep rename to claude/skills/payment/scripts/.gitkeep diff --git a/skills/payment/SKILL.md b/openclaw/skills/payment/SKILL.md similarity index 98% rename from skills/payment/SKILL.md rename to openclaw/skills/payment/SKILL.md index 013bc1f..207127d 100644 --- a/skills/payment/SKILL.md +++ b/openclaw/skills/payment/SKILL.md @@ -7,8 +7,6 @@ description: Request and receive payments. Use this skill when you need to reque This skill enables you to request and accept payments in USDC, a US Dollar pegged stable coin. -**NOTE:** If you are Claude Code, set `{baseDir}` as `.` -- the directory where this `SKILL.md` file is located in. - **NOTE:** Amounts are in human-readable units. For example, `--amount 1.5` means 1.5 USDC. ## Workflow diff --git a/openclaw/skills/payment/bootstrap.sh b/openclaw/skills/payment/bootstrap.sh new file mode 100755 index 0000000..9e31da4 --- /dev/null +++ b/openclaw/skills/payment/bootstrap.sh @@ -0,0 +1,150 @@ +#!/bin/bash +# Bootstrap script for x402 tools +# Downloads and installs platform-specific binaries + +set -e + +REPO="second-state/payment-skill" +SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SCRIPTS_DIR="${SKILL_DIR}/scripts" + +# Detect platform +detect_platform() { + local os arch + + # Detect OS + case "$(uname -s)" in + Linux*) os="linux" ;; + Darwin*) os="darwin" ;; + MINGW*|MSYS*|CYGWIN*) os="windows" ;; + *) + echo "Error: Unsupported operating system: $(uname -s)" >&2 + exit 1 + ;; + esac + + # Detect architecture + case "$(uname -m)" in + x86_64|amd64) arch="x86_64" ;; + aarch64|arm64) arch="aarch64" ;; + *) + echo "Error: Unsupported architecture: $(uname -m)" >&2 + exit 1 + ;; + esac + + echo "${os}-${arch}" +} + +# Get the download URL for the latest release +get_download_url() { + local platform="$1" + local artifact_name="payment-${platform}.zip" + + # Try to get latest release URL using GitHub API + local api_url="https://api.github.com/repos/${REPO}/releases/latest" + local download_url + + if command -v curl &>/dev/null; then + download_url=$(curl -sL "$api_url" | grep -o "https://github.com/${REPO}/releases/download/[^\"]*${artifact_name}" | head -1) + elif command -v wget &>/dev/null; then + download_url=$(wget -qO- "$api_url" | grep -o "https://github.com/${REPO}/releases/download/[^\"]*${artifact_name}" | head -1) + else + echo "Error: Neither curl nor wget found. Please install one of them." >&2 + exit 1 + fi + + if [ -z "$download_url" ]; then + echo "Error: Could not find release for platform ${platform}" >&2 + echo "Please check https://github.com/${REPO}/releases for available downloads." >&2 + exit 1 + fi + + echo "$download_url" +} + +# Download and extract binaries +download_binaries() { + local platform="$1" + local url="$2" + local temp_dir + local zip_file + + echo "Downloading x402 tools for ${platform}..." >&2 + + # Create scripts directory if it doesn't exist + mkdir -p "${SCRIPTS_DIR}" + + # Create temp directory + temp_dir=$(mktemp -d) + zip_file="${temp_dir}/payment-${platform}.zip" + + # Download + echo "Fetching from: ${url}" >&2 + if command -v curl &>/dev/null; then + curl -sL -o "$zip_file" "$url" + else + wget -q -O "$zip_file" "$url" + fi + + # Extract + echo "Extracting binaries..." >&2 + if command -v unzip &>/dev/null; then + unzip -q -o "$zip_file" -d "${SCRIPTS_DIR}" + else + echo "Error: unzip not found. Please install unzip." >&2 + rm -rf "$temp_dir" + exit 1 + fi + + # Make binaries executable (not needed on Windows) + if [[ "$(uname -s)" != MINGW* ]] && [[ "$(uname -s)" != MSYS* ]] && [[ "$(uname -s)" != CYGWIN* ]]; then + find "${SCRIPTS_DIR}" -maxdepth 1 -type f ! -name ".*" -exec chmod +x {} \; + fi + + # Cleanup + rm -rf "$temp_dir" + + echo "x402 tools installed successfully to ${SCRIPTS_DIR}" >&2 +} + +# Ensure config file exists +ensure_config() { + local config_file="${SKILL_DIR}/config.toml" + local default_config="${SKILL_DIR}/config-default.toml" + + if [ ! -f "$config_file" ]; then + echo "Creating default config at ${config_file}..." >&2 + + # Copy default config + if [ -f "$default_config" ]; then + cp "$default_config" "$config_file" + chmod 600 "$config_file" + echo "Default config created (base-mainnet with USDC)" >&2 + else + echo "Warning: Default config not found at ${default_config}" >&2 + fi + fi +} + +# Main +main() { + # Ensure config exists before anything else + ensure_config + + local platform + platform=$(detect_platform) + echo "Detected platform: ${platform}" >&2 + + local download_url + download_url=$(get_download_url "$platform") + + download_binaries "$platform" "$download_url" + + # List installed binaries + echo "" >&2 + echo "Installed tools:" >&2 + ls -1 "${SCRIPTS_DIR}" | grep -v '^\.' >&2 +} + +main "$@" diff --git a/openclaw/skills/payment/config-default.toml b/openclaw/skills/payment/config-default.toml new file mode 100644 index 0000000..13b4bb4 --- /dev/null +++ b/openclaw/skills/payment/config-default.toml @@ -0,0 +1,13 @@ +[wallet] +path = "wallet.json" +password_file = "password.txt" + +[network] +name = "base-mainnet" +chain_id = 8453 +rpc_url = "https://mainnet.base.org" + +[payment] +default_token = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" +default_token_symbol = "USDC" +default_token_decimals = 6 diff --git a/skills/payment/install.md b/openclaw/skills/payment/install.md similarity index 96% rename from skills/payment/install.md rename to openclaw/skills/payment/install.md index bb31370..b2e74de 100644 --- a/skills/payment/install.md +++ b/openclaw/skills/payment/install.md @@ -18,7 +18,7 @@ mkdir -p "$SKILL_DIR" # Clone the skill directory git clone --depth 1 https://github.com/second-state/payment-skill.git /tmp/payment-skill-repo -cp -r /tmp/payment-skill-repo/skills/payment/* "$SKILL_DIR" +cp -r /tmp/payment-skill-repo/openclaw/skills/payment/* "$SKILL_DIR" rm -rf /tmp/payment-skill-repo # Download platform-specific binaries diff --git a/openclaw/skills/payment/scripts/.gitignore b/openclaw/skills/payment/scripts/.gitignore new file mode 100644 index 0000000..a505259 --- /dev/null +++ b/openclaw/skills/payment/scripts/.gitignore @@ -0,0 +1,4 @@ +# Ignore downloaded binaries (they are downloaded on first use) +* +!.gitignore +!.gitkeep diff --git a/openclaw/skills/payment/scripts/.gitkeep b/openclaw/skills/payment/scripts/.gitkeep new file mode 100644 index 0000000..e69de29