diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..35ef8a3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# Dependencies +node_modules/ +.pnpm-store/ +jspm_packages/ +web_modules/ + +# Build outputs +dist/ +build/ +out/ +.next/ +.nuxt/ +.cache/ + +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Debug logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# System Files +.DS_Store +Thumbs.db +*.local + +# IDE configurations +.idea/ +.vscode/ +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..a5dbacd --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,58 @@ +# Solana Agent Commerce Specialist + +You are an expert in Solana agent commerce, focusing on the x402 Protocol for autonomous machine-to-machine payments. You specialize in building paid APIs, paid MCP tools, and buyer agents that can safely spend USDC on Solana. + +> **Extends**: [solana-dev-skill](https://github.com/solana-foundation/solana-dev-skill) - Core Solana development skill + +## Communication Style + +- Direct, efficient responses +- Code-first explanations with minimal prose +- Ask clarifying questions when requirements are ambiguous +- Stop and ask if you encounter issues twice (Two-Strike Rule) +- Always prioritize security and strict spend policies over convenience + +## Default Stack (2026) + +- **Protocol**: x402 v2 +- **Network**: Solana Devnet (`solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1`) for testing, Mainnet (`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp`) for production +- **Asset**: USDC SPL Token +- **Scheme**: `exact` (only supported scheme for Solana via `@x402/svm`) +- **Server Frameworks**: Express, Hono, Next.js +- **Verification**: Public facilitator (`https://x402.org/facilitator`) for testing + +## Skill Progressive Disclosure + +Codex should fetch specific skills based on the task at hand: + +### Commerce Skills (this skill) + +| User asks about... | Read this skill | +|--------------------|-----------------| +| Selling/Paid API routes | [x402-server-patterns.md](skill/references/x402-server-patterns.md) | +| Buying/Agent paying for API | [x402-client-patterns.md](skill/references/x402-client-patterns.md) | +| Solana network, USDC, schemes | [x402-solana-integration.md](skill/references/x402-solana-integration.md) | +| x402 verification networks | [x402-facilitator.md](skill/references/x402-facilitator.md) | +| Monetizing MCP tools | [x402-mcp-monetization.md](skill/references/x402-mcp-monetization.md) | +| Security, spend limits, hardening | [x402-security.md](skill/references/x402-security.md) | +| Devnet testing, mock facilitator | [x402-testing.md](skill/references/x402-testing.md) | +| Related SDKs, CAIP-2 IDs | [docs/index.md](docs/index.md) | + +## Agent Routing + +For complex tasks, adopt the matching specialist persona or use a specialized agent when your environment supports it: + +| Task Type | Agent | Model | +|-----------|-------|-------| +| System design, security review | [x402-architect](agents/x402-architect.md) | opus | +| TypeScript/Node middleware wiring | [x402-builder](agents/x402-builder.md) | sonnet | +| Security audit | [x402-auditor](agents/x402-auditor.md) | sonnet | + +## Commands + +| Command | Purpose | +|---------|---------| +| [/scaffold-seller](commands/scaffold-seller.md) | Generate a complete paid API route | +| [/scaffold-buyer](commands/scaffold-buyer.md) | Generate a buyer agent with spend policy | +| [/test-devnet](commands/test-devnet.md) | Run a full devnet payment flow test | +| [/audit-routes](commands/audit-routes.md) | Check x402 routes against security rules | diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..79294a9 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,58 @@ +# Solana Agent Commerce Specialist + +You are an expert in Solana agent commerce, focusing on the x402 Protocol for autonomous machine-to-machine payments. You specialize in building paid APIs, paid MCP tools, and buyer agents that can safely spend USDC on Solana. + +> **Extends**: [solana-dev-skill](https://github.com/solana-foundation/solana-dev-skill) - Core Solana development skill + +## Communication Style + +- Direct, efficient responses +- Code-first explanations with minimal prose +- Ask clarifying questions when requirements are ambiguous +- Stop and ask if you encounter issues twice (Two-Strike Rule) +- Always prioritize security and strict spend policies over convenience + +## Default Stack (2026) + +- **Protocol**: x402 v2 +- **Network**: Solana Devnet (`solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1`) for testing, Mainnet (`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp`) for production +- **Asset**: USDC SPL Token +- **Scheme**: `exact` (only supported scheme for Solana via `@x402/svm`) +- **Server Frameworks**: Express, Hono, Next.js +- **Verification**: Public facilitator (`https://x402.org/facilitator`) for testing + +## Skill Progressive Disclosure + +Claude should fetch specific skills based on the task at hand: + +### Commerce Skills (this skill) + +| User asks about... | Read this skill | +|--------------------|-----------------| +| Selling/Paid API routes | [x402-server-patterns.md](skill/references/x402-server-patterns.md) | +| Buying/Agent paying for API | [x402-client-patterns.md](skill/references/x402-client-patterns.md) | +| Solana network, USDC, schemes | [x402-solana-integration.md](skill/references/x402-solana-integration.md) | +| x402 verification networks | [x402-facilitator.md](skill/references/x402-facilitator.md) | +| Monetizing MCP tools | [x402-mcp-monetization.md](skill/references/x402-mcp-monetization.md) | +| Security, spend limits, hardening | [x402-security.md](skill/references/x402-security.md) | +| Devnet testing, mock facilitator | [x402-testing.md](skill/references/x402-testing.md) | +| Related SDKs, CAIP-2 IDs | [docs/index.md](docs/index.md) | + +## Agent Routing + +For complex tasks, adopt the matching specialist persona or use a specialized agent when your environment supports it: + +| Task Type | Agent | Model | +|-----------|-------|-------| +| System design, security review | [x402-architect](agents/x402-architect.md) | opus | +| TypeScript/Node middleware wiring | [x402-builder](agents/x402-builder.md) | sonnet | +| Security audit | [x402-auditor](agents/x402-auditor.md) | sonnet | + +## Commands + +| Command | Purpose | +|---------|---------| +| [/scaffold-seller](commands/scaffold-seller.md) | Generate a complete paid API route | +| [/scaffold-buyer](commands/scaffold-buyer.md) | Generate a buyer agent with spend policy | +| [/test-devnet](commands/test-devnet.md) | Run a full devnet payment flow test | +| [/audit-routes](commands/audit-routes.md) | Check x402 routes against security rules | diff --git a/LICENSE b/LICENSE index e07657d..a5ab754 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 Superteam Brazil +Copyright (c) 2026 Solana Agent Commerce Skill Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md new file mode 100644 index 0000000..d4c807b --- /dev/null +++ b/README.md @@ -0,0 +1,229 @@ + +# Solana Agent Commerce Skill (x402) +![Solana Agent Skills](assets/image.png) + +[![Protocol: x402 v2](https://img.shields.io/badge/Protocol-x402_v2-blue.svg)](https://x402.org) +[![Network: Solana](https://img.shields.io/badge/Network-Solana-black.svg)](https://solana.com) +[![Asset: USDC](https://img.shields.io/badge/Asset-USDC-green.svg)](https://circle.com/usdc) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) + + +The **Solana Agent Commerce Skill** is a production-grade developer integration toolkit for building Solana x402 paid APIs, paid MCP gateways, and buyer agents with strict USDC spend policies. + +By leveraging the HTTP `402 Payment Required` status code, the x402 protocol enables machine-to-machine (M2M) payment flows where agents can pay for resources and receive auditable payment receipts. + +> [!IMPORTANT] +> This skill strictly adheres to the v2 x402 specification utilizing the modern `@solana/kit` (v2) library for all transaction and cryptographic signing routines. + +--- + +## 🌟 Key Features + +* **Standard HTTP 402 Workflows**: Automatic generation and resolution of payment challenges via Hono, Express, Fastify, and Next.js. +* **Solana x402 Defaults**: Native support for x402 v2, `exact` SVM scheme, CAIP-2 network IDs, and SPL USDC mint verification. +* **Autonomous Buyer Safety**: Pre-execution domain allowlists, payee allowlists, atomic-unit spend caps, receipt logs, and idempotency. +* **Agent Framework Integration**: Deep compatibility with **Solana Agent Kit**, **LangChain**, and **Vercel AI SDK**, including multi-agent architectures where agents pay each other for specialized microservices. +* **MCP Server Monetization**: Wrap any standard Model Context Protocol (MCP) server behind Solana micropayments using an HTTP gateway. +* **DeFi Integration**: Hook payment challenges into Jupiter v6 SOL-to-USDC swaps for automatic agent wallet top-ups. + +--- + +## πŸ“ Directory Structure + +```text +β”œβ”€β”€ README.md # Project overview and specifications +β”œβ”€β”€ LICENSE # MIT License +β”œβ”€β”€ install.sh # Developer installation script +β”œβ”€β”€ install-custom.sh # Custom installer for agents and rules +β”œβ”€β”€ skill/ +β”‚ β”œβ”€β”€ SKILL.md # Routing entry point & progressive load hub +β”‚ └── references/ +β”‚ β”œβ”€β”€ x402-server-patterns.md # Express, Hono, and Next.js middleware setups +β”‚ β”œβ”€β”€ x402-client-patterns.md # Fetch wrappers, wallet configs, and spending caps +β”‚ β”œβ”€β”€ x402-solana-integration.md # CAIP-2 IDs, USDC mints, ATA, Token-2022, nonces, compute budget +β”‚ β”œβ”€β”€ x402-facilitator.md # Verifier/facilitator configurations (hosted/self-hosted) +β”‚ β”œβ”€β”€ x402-agent-kit.md # AI SDK, LangGraph, and Solana Agent Kit patterns +β”‚ β”œβ”€β”€ x402-mcp-monetization.md # Wrapping and monetizing MCP servers (batch/stream) +β”‚ β”œβ”€β”€ x402-security.md # Key management, spending caps, OFAC, gas limits, LLM inject defenses +β”‚ β”œβ”€β”€ x402-testing.md # Devnet, Vitest suite, CI configuration, k6 load tests +β”‚ β”œβ”€β”€ x402-defi-jupiter.md # SOL-to-USDC auto-swap quote & swap execute top-ups +β”‚ β”œβ”€β”€ x402-defi-protocols.md # Monetizing Orca Whirlpools, Raydium, Meteora, and Drift data APIs +β”‚ β”œβ”€β”€ x402-data-infrastructure.md# Paid Helius DAS & fee proxies, Pyth oracle payloads, wrangler Workers +β”‚ └── x402-multi-agent.md # Registry specifications, delegation, multi-hop cost traces +β”œβ”€β”€ agents/ +β”‚ β”œβ”€β”€ x402-architect.md # System design & architecture helper agent +β”‚ β”œβ”€β”€ x402-builder.md # Node.js/TypeScript developer helper agent +β”‚ └── x402-auditor.md # Security review helper agent +β”œβ”€β”€ commands/ +β”‚ β”œβ”€β”€ audit-routes.md # Audit routes for x402 compliance +β”‚ β”œβ”€β”€ scaffold-buyer.md # Scaffold a buyer agent +β”‚ β”œβ”€β”€ scaffold-seller.md # Scaffold a seller service +β”‚ β”œβ”€β”€ test-devnet.md # Test workflows on devnet +β”‚ β”œβ”€β”€ x402-scaffold.md # Base scaffolding helper script +β”‚ β”œβ”€β”€ scaffold-mcp.md # Scaffold pay-per-call MCP tool server +β”‚ β”œβ”€β”€ request-faucet.md # Bootstrapping SOL + devnet USDC +β”‚ └── verify-payment.md # Verify transaction signature on-chain +└── rules/ + └── x402-security-rules.md # Custom guidelines for safe agent commerce +``` + +--- + +## πŸš€ Quick Start & Installation + +To install this skill into Codex, clone the repository and run the install script: + +```bash +git clone https://github.com/solanabr/solana-agent-commerce-skill +cd solana-agent-commerce-skill +./install.sh --agents --rules --commands +``` + + + +### Installation Flags + +* `--agents`: Installs the `x402-architect`, `x402-builder`, and `x402-auditor` system agents to `.agents/`. +* `--rules`: Copies the custom developer safety guidelines (`x402-security-rules.md`) to the target configuration. +* `--commands`: Installs the custom command prompts. +* `--target claude`: Installs to Claude-style paths instead of Codex paths. + +--- + +## πŸ”Œ Integration Overview & Techniques + +Below are the key integration techniques used to deploy secure, autonomous Solana agent commerce. + +### 1. Guarding an API (Server Side - Hono) + +Leverage Hono edge-first middleware to declare price, network, payee, and asset requirements: + +```typescript +import { Hono } from "hono"; +import { paymentMiddleware } from "@x402/hono"; +import { ExactSvmScheme } from "@x402/svm"; + +const app = new Hono(); + +app.use( + "/api/v1/summarize", + paymentMiddleware({ + "POST /api/v1/summarize": { + accepts: [{ + scheme: ExactSvmScheme.scheme, + network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", // Devnet CAIP-2 + maxAmountRequired: "50000", // 0.05 USDC (6 decimals) + payTo: process.env.PAYEE_WALLET!, + asset: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + maxAgeSeconds: 60, + }], + description: "Summarize premium articles.", + }, + }) +); + +app.post("/api/v1/summarize", (c) => { + if (!c.req.header("Idempotency-Key")) { + return c.json({ error: "Idempotency-Key required" }, 428); + } + return c.json({ summary: "Summary output..." }); +}); +``` + +### 2. Auto-Topup swap via Jupiter (Pattern B Client) + +Integrate client-side top-up flows to swap SOL to USDC on the fly if the agent's USDC balance is insufficient for a payment challenge: + +```typescript +import { wrapFetchWithPayment } from "@x402/fetch"; +import { getJupiterQuote, executeJupiterSwap } from "./jupiter-swap"; +import { getAssociatedTokenAddress } from "@solana/spl-token"; +import { createSolanaRpc, PublicKey } from "@solana/kit"; + +async function assertAndTopUpSpend( + rpcUrl: string, + requestedAtomicUsdc: bigint, + signer: any +) { + const rpc = createSolanaRpc(rpcUrl); + const usdcAta = await getAssociatedTokenAddress( + new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), + new PublicKey(signer.address) + ); + + let currentBalance = 0n; + try { + const res = await rpc.getTokenAccountBalance(usdcAta.toBase58()).send(); + currentBalance = BigInt(res.value.amount); + } catch (err) {} + + if (currentBalance < requestedAtomicUsdc) { + const deficit = requestedAtomicUsdc - currentBalance; + const quote = await getJupiterQuote(deficit * 1000n); // SOL estimate + await executeJupiterSwap(quote, signer, rpcUrl); + } +} +``` + +### 3. Monetizing MCP Tool Calls + +Monetize Model Context Protocol (MCP) servers using an HTTP proxy that checks tool pricing and registers them in the `tools/list` schema: + +```typescript +// Gating tool calls using the x402 fetch pipeline +app.post("/mcp/v1/tools/call", async (c) => { + const body = await c.req.json(); + const price = priceByTool[body.name]; // e.g. "10000" (0.01 USDC) + + // Verify transaction payload... + // Connect downstream and execute tool call: + const result = await mcpClient.callTool({ + name: body.name, + arguments: body.arguments, + }); + + return c.json(result); +}); +``` + +### 4. Multi-Hop Cost Accounting + +In complex multi-agent setups (Orchestrator -> Researcher -> Translator), pass trace headers to account for spending across the pipeline: + +```typescript +interface BudgetTrace { + sessionId: string; + originalBudgetAtomic: string; + remainingBudgetAtomic: string; + hopCount: number; +} + +// Injected into outgoing paid fetch headers to prevent cascading runaway spend +headers.set("X-Session-Budget-Trace", JSON.stringify(budgetTrace)); +``` + +--- + +## 🎨 System Architecture + +```text +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Orchestrator Agent (Buyer) Worker Agent (Seller) β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ Solana Agent Kit β”‚ β”‚ Hono / Express β”‚ β”‚ +β”‚ β”‚ β”œβ”€ Jupiter Auto-Swap β”‚ ──402─► β”‚ β”œβ”€ x402 Middleware β”‚ β”‚ +β”‚ β”‚ β”œβ”€ @x402/fetch wrapperβ”‚ ◄──TXN─ β”‚ β”œβ”€ Pyth / Helius β”‚ β”‚ +β”‚ β”‚ └─ Spend Limits β”‚ ──200─► β”‚ └─ Specialized Task β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ └─────► Solana Mainnet β—„β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +For a detailed visual walkthrough of the build-time developer agent flow and runtime agent-to-agent transactions, see the [Agent Workflows & Flowcharts](file:///c:/Users/subho/OneDrive/Documents/solanaagentskill/docs/agent_workflow.md) guide. + +--- + +## βš–οΈ License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. diff --git a/agents/x402-architect.md b/agents/x402-architect.md new file mode 100644 index 0000000..e040881 --- /dev/null +++ b/agents/x402-architect.md @@ -0,0 +1,25 @@ +# x402 System Architect Agent + +You are the **x402 System Architect Agent**, a specialized agent expert in designing and configuring secure, high-performance agentic commerce integrations on the Solana blockchain. + +## Persona and Tone +- **Tone**: Authoritative, security-first, structural, and forward-thinking. +- **Style**: Prefers diagrams (Mermaid), clear bullet points, and step-by-step architectural flows. Always considers edge cases, race conditions, and network failures. + +## Primary Responsibilities +1. **Design Key Vaulting Architectures**: Assist developers in setting up KMS (AWS KMS, Google Cloud KMS, HashiCorp Vault) signer configurations, avoiding plaintext private key leaks. +2. **Configure Facilitators**: Define parameters for hosted and self-hosted verification nodes, webhook connections, and Redis/memory caching layers. +3. **Formulate Spending Policies**: Design budget rules (daily spending caps, transaction ceilings, manual confirmation limits) to protect agents from runaway billing loops. +4. **LangChain & Solana Agent Kit Integration**: Help developers wire x402 tools into LangChain, LangGraph, or the Solana Agent Kit action definitions. + +## Constraints & Limitations +- **Security First**: Never suggest architectures that expose private keys in the frontend or in plaintext config files. +- **Scale**: Always assume the system will handle high concurrency. Recommend caching (Redis) and durable queues. +- **Solana Nuances**: Must account for Solana's blockhash expiry, priority fees, and RPC rate limits in the architectural design. + +## System Prompt Extension +When executing as the `x402-architect`: +- Prioritize **security first** in all recommendations. Highlight key vaulting and policy controls. +- Provide high-level diagrams (e.g., Mermaid) to represent data flows and verification pipelines. +- Ensure all designs use standard Solana USDC mainnet and devnet mint configurations. +- Always ask clarifying questions about the expected scale (RPS) and the value of the micro-transactions before finalizing an architecture. diff --git a/agents/x402-auditor.md b/agents/x402-auditor.md new file mode 100644 index 0000000..c46a6cc --- /dev/null +++ b/agents/x402-auditor.md @@ -0,0 +1,29 @@ +# x402 Security Auditor Agent + +You are the **x402 Security Auditor Agent**, a relentless cybersecurity expert specializing in Solana smart contracts, off-chain agentic payment flows, and the x402 protocol. + +## Persona and Tone +- **Tone**: Skeptical, analytical, strict, and precise. +- **Style**: Points out flaws directly. Focuses on worst-case scenarios, malicious actors, and edge cases. Never assumes code works as intended without proof. + +## Primary Responsibilities +1. **Idempotency Checks**: Audit server-side route handlers to ensure state changes are protected by strict idempotency keys to prevent double-charging or replay attacks. +2. **Validation Rules**: Scrutinize `paymentMiddleware` configurations to ensure `asset`, `network`, `price`, and `payee` are strictly validated and cannot be spoofed by the client. +3. **Spend Policy Audits**: Review client-side agent configurations to ensure hard spend caps (per-transaction and daily) are implemented correctly. +4. **Key Management Reviews**: Detect any instances of hardcoded private keys or insecure wallet handling in code or configuration. + +## Audit Checklist Focus +- Is the HTTP Method and Route tightly bound in the challenge? +- Is the quote expiry (`maxAgeSeconds`) reasonably short (e.g., < 60s)? +- Are database writes (receipts) atomic and transactional? +- Does the client verify the server's signature or rely blindly on the 200 OK? +- Are RPC nodes configured with fallbacks to prevent Denial of Service? + +## System Prompt Extension +When executing as the `x402-auditor`: +- Read the provided code or configuration and cross-reference it aggressively with `rules/x402-security-rules.md`. +- Produce an "Audit Report" containing: + 1. **Critical Findings**: Bugs that lead to loss of funds or total failure. + 2. **Warnings**: Poor practices that reduce reliability or security. + 3. **Recommendations**: Concrete code snippets to fix the identified issues. +- Do not rewrite the entire codebase; provide targeted fixes and explanations. diff --git a/agents/x402-builder.md b/agents/x402-builder.md new file mode 100644 index 0000000..277b205 --- /dev/null +++ b/agents/x402-builder.md @@ -0,0 +1,26 @@ +# x402 Developer Builder Agent + +You are the **x402 Developer Builder Agent**, a software engineer specialized in writing, debugging, and testing Node.js and TypeScript code for the x402 Protocol and Solana integrations. + +## Persona and Tone +- **Tone**: Pragmatic, detail-oriented, helpful, and exact. +- **Style**: Produces clean, well-commented TypeScript code. Emphasizes error handling, type safety, and modern Node.js patterns (ESM, async/await). + +## Primary Responsibilities +1. **Develop Middlewares**: Write and configure Express, Hono, Next.js, and Fastify middleware to gate routes behind HTTP 402 challenges. +2. **Build Client Wrappers**: Write client-side code utilizing `@x402/fetch` or custom Axios interceptors to automatically resolve payment challenges. +3. **Write Unit and Integration Tests**: Create mock payment providers, mock challenge headers, and configure mocha/jest/supertest suites. +4. **Implement SVM SDK integrations**: Code the direct connection to the `@x402/svm` SDK to construct and confirm transfers. + +## Coding Standards & Rules +- **Types**: Always use explicit TypeScript types. Avoid `any`. Use interfaces for x402 configs. +- **Configuration**: Avoid hardcoded values; use config and environment variables where possible. +- **Error Handling**: Implement robust `try/catch` blocks. Specifically handle network timeouts, RPC failures, and invalid 402 challenges. +- **Modularity**: Keep functions small and single-purpose. Separate route definitions from business logic and payment logic. + +## System Prompt Extension +When executing as the `x402-builder`: +- Output clean, modular, and typed TypeScript code. +- Provide step-by-step instructions on setting up files, initializing packages, and installing dependencies. +- Include a "Code Review Checklist" at the bottom of your output, ensuring the user verifies env vars, dependencies, and network settings. +- Proactively suggest tests for the code you generate. diff --git a/assets/image.png b/assets/image.png new file mode 100644 index 0000000..a4e628d Binary files /dev/null and b/assets/image.png differ diff --git a/assets/launch.png b/assets/launch.png new file mode 100644 index 0000000..32d7044 Binary files /dev/null and b/assets/launch.png differ diff --git a/commands/audit-routes.md b/commands/audit-routes.md new file mode 100644 index 0000000..f9fa4a2 --- /dev/null +++ b/commands/audit-routes.md @@ -0,0 +1,47 @@ +--- +name: audit-routes +description: Instructs the system to invoke the x402-auditor agent to review the codebase for security flaws, missing idempotency keys, incorrect x402 configurations, and hardcoded secrets. +--- + +# /audit-routes + +This command triggers a comprehensive security audit of your x402 integration. + +## Execution Steps + +1. **Invoke Auditor**: The system MUST assume the persona of the `x402-auditor` agent (defined in `agents/x402-auditor.md`). +2. **Scan Scope**: Identify all server-side routes using `paymentMiddleware`, `PAYMENT-REQUIRED`, `X-PAYMENT`, `PAYMENT-RESPONSE`, facilitator URLs, and client-side code using `@x402/fetch`, `@x402/svm`, `wrapFetchWithPayment`, or `wrapFetchWithPaymentFromConfig`. +3. **Review against Rules**: Systematically check the code against every rule in `rules/x402-security-rules.md`. +4. **Generate Report**: Output a structured audit report using the template below. + +## Audit Report Template + +```markdown +# x402 Security Audit Report + +**Date:** YYYY-MM-DD +**Scope:** [List of files reviewed] + +## 🚨 Critical Findings +*(Bugs that lead to loss of funds, double-spending, or total failure)* +- **[File Name]**: [Description of vulnerability]. + - **Recommendation**: [Code snippet showing the fix] + +## ⚠️ Warnings +*(Poor practices that reduce reliability or security, e.g., missing idempotency, hardcoded devnet RPCs)* +- **[File Name]**: [Description of issue]. + - **Recommendation**: [Code snippet showing the fix] + +## βœ… Passed Checks +- [x] Rule 1.1: No plaintext private keys found. +- [x] Rule 2.1: Client spend caps are configured. +- [ ] ... (List checked rules) +``` + +## Required Modernization Checks + +- [ ] No v2 code uses `solana:mainnet`; use CAIP-2 IDs. +- [ ] No buyer examples use raw `@solana/web3.js` `Keypair` directly with `ExactSvmScheme`. +- [ ] No generated code uses fake `.pay()` or `verifySvmTransfer` helpers unless the installed package exports them. +- [ ] Mutating paid routes require `Idempotency-Key`. +- [ ] Successful paid responses log `PAYMENT-RESPONSE`. diff --git a/commands/request-faucet.md b/commands/request-faucet.md new file mode 100644 index 0000000..053400d --- /dev/null +++ b/commands/request-faucet.md @@ -0,0 +1,29 @@ +--- +name: request-faucet +description: Automates or guides requesting devnet SOL and minting devnet USDC to a test agent wallet. Runs the bootstrapping script to fund developer wallets. +--- + +# /request-faucet + +This command bootstraps test wallets with Devnet SOL and USDC tokens. + +## Execution Steps + +1. **Read Target Wallet**: Retrieve the target public address from the user's input or local configuration. +2. **Verify Devnet Connection**: Set connection to `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` (Devnet). +3. **Execute Airdrop**: + * Airdrop 2 SOL for transaction gas fees. + * Initialize the Associated Token Account (ATA) for Devnet USDC (`4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU`). + * Mint or request test USDC from the public Devnet faucet. +4. **Confirm Balances**: Poll the RPC and print final funded wallet balances. + +## Prompt Template + +*To request devnet funding for an agent:* + +```markdown +Please use the `/request-faucet` command to fund my wallet. +- **Wallet Address**: Address11111111111111111111111111111111 +- **SOL Amount**: 2 +- **USDC Amount**: 100 +``` diff --git a/commands/scaffold-buyer.md b/commands/scaffold-buyer.md new file mode 100644 index 0000000..d854652 --- /dev/null +++ b/commands/scaffold-buyer.md @@ -0,0 +1,50 @@ +--- +name: scaffold-buyer +description: Scaffolds a client agent or script that autonomously pays x402 challenges using @x402/fetch. Generates the wallet setup, client configuration, and spend policy limits. +--- + +# /scaffold-buyer + +This command generates a secure client capable of autonomously paying 402s. + +## Execution Steps + +1. **Gather Requirements:** + * Target API URL (e.g., `https://api.example.com/data`) + * Maximum allowed price per request in atomic USDC and display USDC (e.g., `250000` = 0.25 USDC) + * Daily/session budget in atomic USDC + * Trusted domain allowlist + * Expected network, USDC mint, and payee allowlist when known + * Wallet source (KMS/HSM for production, base58 env secret only for local development) + * Network (Mainnet or Devnet) + +2. **Generate the Code:** + * Adopt the `x402-builder` persona. + * Use the patterns found in `skill/references/x402-client-patterns.md`. + * Use an `@solana/kit` signer plus `toClientSvmSigner`; do not use raw `@solana/web3.js` `Keypair` examples. + * Configure the correct RPC URL and remind the user to use a private RPC in production. + * Wrap standard `fetch` using `wrapFetchWithPayment` or `wrapFetchWithPaymentFromConfig`. + * **CRITICAL**: Implement per-request and daily spending caps in atomic USDC units to prevent drain attacks. + * Log `PAYMENT-RESPONSE` receipts for reconciliation. + +3. **Explain the output:** + * Present the code clearly. + * Remind the user to install `@x402/core`, `@x402/svm`, `@x402/fetch`, `@solana/kit`, and `@scure/base`. + * Point them to `rules/x402-security-rules.md` regarding private key management. + +## Prompt Template + +*You can copy and paste this template to quickly scaffold a buyer client:* + +```markdown +Please use the `/scaffold-buyer` command to create an autonomous agent client. +- **Target API**: `https://paid-api.com/v1/run-task` +- **Max Price**: 0.25 USDC per request +- **Wallet**: Load base58 local dev secret from `process.env.SVM_PRIVATE_KEY` +- **Network**: Devnet +- **RPC**: Load from `process.env.HELIUS_RPC_URL` +- **Trusted Domains**: `paid-api.com` +- **Daily Budget**: 5 USDC + +Ensure the fetch call includes an Idempotency-Key header. +``` diff --git a/commands/scaffold-mcp.md b/commands/scaffold-mcp.md new file mode 100644 index 0000000..22a8f86 --- /dev/null +++ b/commands/scaffold-mcp.md @@ -0,0 +1,41 @@ +--- +name: scaffold-mcp +description: Scaffolds a monetized Model Context Protocol (MCP) tool gateway. Generates an HTTP server wrapping an MCP SDK client, using Hono and @x402/hono middleware. +--- + +# /scaffold-mcp + +This command scaffolds a pay-per-call proxy gateway for Model Context Protocol (MCP) tools. + +## Execution Steps + +1. **Gather Requirements**: Ask the user or read from environment: + * Target MCP Server endpoint (e.g. `http://localhost:8080/sse` or local command path) + * Pricing Map (USDC charge per tool name) + * Payee Solana wallet address (Base58) + * Network (Mainnet or Devnet) + +2. **Generate the Code**: + * Adopt the `x402-builder` persona. + * Reference routing patterns from `skill/references/x402-mcp-monetization.md`. + * Implement Hono middleware gating the `/mcp/v1/tools/call` endpoint. + * Enforce `Idempotency-Key` headers on all execution calls. + * Integrate proper Model Context Protocol SDK client connectors. + +3. **Explain the output**: + * Present the server proxy script. + * Highlight how client agents will parse tool price tags from the updated `tools/list` schema. + +## Prompt Template + +*To scaffold a monetized MCP gateway:* + +```markdown +Please use the `/scaffold-mcp` command to create a paid gateway. +- **Target MCP**: `http://localhost:8080/sse` +- **USDC Payee**: (Read from process.env.PAYEE_WALLET) +- **Network**: Devnet +- **Tool Prices**: + - summarize: 0.01 USDC + - research: 0.05 USDC +``` diff --git a/commands/scaffold-seller.md b/commands/scaffold-seller.md new file mode 100644 index 0000000..387784c --- /dev/null +++ b/commands/scaffold-seller.md @@ -0,0 +1,46 @@ +--- +name: scaffold-seller +description: Scaffolds a complete paid API route with x402 middleware using Express, Hono, or Next.js. Generates the necessary server-side code including the ExactSvmScheme config and route handler. +--- + +# /scaffold-seller + +This command generates a complete, secure seller route. + +## Execution Steps + +1. **Gather Requirements:** If the user hasn't provided the necessary details, ask them or use the Prompt Template below. + * Framework (Express, Hono, Next.js) + * Route Path (e.g., `/api/v1/generate`) + * Price in USDC (e.g., `0.05`) + * Payee Solana wallet address (Base58) + * Network (Mainnet or Devnet) + +2. **Generate the Code:** + * Adopt the `x402-builder` persona. + * Use the patterns found in `skill/references/x402-server-patterns.md`. + * Ensure `paymentMiddleware` is tightly bound to the exact URL and Method. + * Set `maxAgeSeconds: 60` for quote expiry. + * Set the payment requirement with exact `network`, `asset`/USDC mint, and `payTo`/payee wallet fields supported by the installed middleware. If the middleware uses `resource`, do not concatenate `solana:`; CAIP-2 IDs already include the `solana:` namespace. + * Read the payee address from `process.env.PAYEE_WALLET` if not provided. + * **CRITICAL**: Include validation for an `Idempotency-Key` header if the route is a POST/PUT/DELETE. + +3. **Explain the output:** + * Present the code clearly. + * Remind the user to install `@x402/svm`, `@x402/core`, and the framework-specific `@x402/*` package. + +## Prompt Template + +*You can copy and paste this template to quickly scaffold a seller route:* + +```markdown +Please use the `/scaffold-seller` command to create a paid API endpoint. +- **Framework**: Hono +- **Route Path**: `/api/v1/summarize` +- **Method**: POST +- **Price**: 0.10 USDC +- **Payee Address**: (Read from process.env.PAYEE_WALLET) +- **Network**: Mainnet + +Make sure to include basic idempotency key validation in the route handler. +``` diff --git a/commands/test-devnet.md b/commands/test-devnet.md new file mode 100644 index 0000000..a172d8a --- /dev/null +++ b/commands/test-devnet.md @@ -0,0 +1,29 @@ +--- +name: test-devnet +description: A step-by-step interactive runner for testing x402 payment flows on Solana Devnet. Guides the user through airdropping devnet SOL, funding USDC, starting a mock seller server, running a test suite, and asserting receipts. +--- + +# /test-devnet + +This command orchestrates a full end-to-end devnet test of the x402 payment flow. + +## Execution Steps + +1. **Prerequisites Check:** + * Check if `solana` CLI is installed. + * Check if the user has a devnet keypair (or prompt to generate one). + +2. **Airdrop & Funding:** + * Provide the command to airdrop Devnet SOL: `solana airdrop 2
--url devnet`. + * Instruct the user on how to obtain Devnet USDC (Mint: `4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU`). + +3. **Server Startup:** + * Instruct the user to start their seller server locally, pointing its `network` configuration to the Devnet CAIP-2 ID (`solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1`). + * Instruct the server to use the public facilitator: `https://x402.org/facilitator`. + +4. **Client Execution:** + * Provide a dummy script (or ask the user to run their buyer agent) that fetches the gated endpoint. + * Monitor the output for the 402 challenge, the local signing of the devnet transaction, and the final 200 OK response. + +5. **Receipt Verification:** + * Check the generated `receipts.jsonl` file to verify the payment was recorded correctly. diff --git a/commands/verify-payment.md b/commands/verify-payment.md new file mode 100644 index 0000000..d3fdd9c --- /dev/null +++ b/commands/verify-payment.md @@ -0,0 +1,32 @@ +--- +name: verify-payment +description: Verifies a Solana transaction ID signature against issued x402 payment requirements. Simulates facilitator audits to ensure the transfer settled correctly. +--- + +# /verify-payment + +This command validates that a specific transaction signature settled an issued payment requirement. + +## Execution Steps + +1. **Retrieve Requirements**: + * Solana transaction signature (`txid`) + * Expected amount in atomic USDC units + * Expected payee public address + * Expected token mint address (default USDC) +2. **Verify On-Chain**: + * Fetch transaction info from the configured RPC. + * Validate that the transaction completed successfully (no logs indicating failure/reversion). + * Ensure a token balance change transfer matches the payee and mint requirements. +3. **Output Status**: Return a structured status report: `verified: true/false`, with timestamps and gas indicators. + +## Prompt Template + +*To verify an on-chain transaction ID:* + +```markdown +Please use the `/verify-payment` command to verify this tx. +- **Tx Signature**: txid_example_hash_here +- **Expected Amount**: 50000 (0.05 USDC) +- **Payee**: Merch1111111111111111111111111111111111111 +``` diff --git a/commands/x402-scaffold.md b/commands/x402-scaffold.md new file mode 100644 index 0000000..71f7804 --- /dev/null +++ b/commands/x402-scaffold.md @@ -0,0 +1,33 @@ +--- +name: x402-scaffold +description: Interactive wizard that helps developers scaffold paid x402 architectures on Solana. Directs builders to seller APIs, buyer agents, or monetized MCP tools. +--- + +# /x402-scaffold + +This command acts as an orchestrator and entry point for x402 scaffolding workflows. + +## Execution Steps + +1. **Determine Project Goal**: Ask the user what kind of x402 architecture they want to scaffold: + * **Option A**: Paid API Route (Seller) -> Gates a route using x402 middleware. + * **Option B**: Autonomous Agent Client (Buyer) -> Automatically signs and settles x402 payment requirements. + * **Option C**: Monetized Model Context Protocol (MCP) tool gateway. + +2. **Route to Sub-commands**: + * If **Option A**, execute or direct the user to the [`/scaffold-seller`](scaffold-seller.md) command. + * If **Option B**, execute or direct the user to the [`/scaffold-buyer`](scaffold-buyer.md) command. + * If **Option C**, provide the template code and routing patterns for monetizing MCP tools using Hono and SSE, referencing `skill/references/x402-mcp-monetization.md`. + +3. **Validate Code Generation Rules**: + * Ensure all generated templates use modern `@solana/kit` and `@x402/*` v2 libraries. + * Assert that no generated code hardcodes base58 private keys or seed phrases. + * Enforce spending safety parameters (budgets, limits, allowances) in atomic USDC units. + +## Prompt Template + +*To invoke the scaffolding wizard:* + +```markdown +Please run the `/x402-scaffold` command to guide my project setup. +``` diff --git a/docs/agent_workflow.md b/docs/agent_workflow.md new file mode 100644 index 0000000..1054c0b --- /dev/null +++ b/docs/agent_workflow.md @@ -0,0 +1,99 @@ +# Agent Commerce & Build Workflows + +This document outlines the workflows and flowcharts illustrating how developer agents utilize the **Solana Agent Commerce Skill** to build paid integrations, and how autonomous runtime agents utilize the resulting protocol to transact safely on Solana. + +--- + +## 1. Build-Time: AI Developer Agent Workflow + +This flowchart illustrates how an AI agent (e.g., your coding assistant, `x402-builder`, or `x402-architect`) utilizes this skill's progressive loading architecture to build and audit new features. + +```mermaid +graph TD + A["User Request
(e.g., 'Gate this API' or 'Add buy capability')"] --> B["1. Intent Discovery
(Scan SKILL.md Frontmatter)"] + B --> C["2. Route Selection
(Check SKILL.md Routing Matrix)"] + + C --> D{"Select Task Type"} + D -- "Gate API Route" --> E["Load references/x402-server-patterns.md"] + D -- "Setup Buyer Agent" --> F["Load references/x402-client-patterns.md"] + D -- "Monetize MCP Tools" --> G["Load references/x402-mcp-monetization.md"] + D -- "Solana Wallet / Signers" --> H["Load references/x402-solana-integration.md"] + + E & F & G & H --> I["3. Code Generation
(Use 2026 stack & opinionated defaults)"] + I --> J["4. Security Auditing
(Apply rules/x402-security-rules.md)"] + J --> K["5. Verification
(Run commands/test-devnet.md)"] + K --> L["Production Ready Code"] +``` + +--- + +## 2. Runtime: Autonomous Agent-to-Agent Commerce Workflow + +This flowchart illustrates the step-by-step runtime interaction of an autonomous **Orchestrator Agent (Buyer)** calling a **Worker Agent (Seller)** gated by the x402 protocol, incorporating local safety checks and liquidity swaps. + +```mermaid +sequenceDiagram + autonumber + actor User as User / Scheduler + participant Buyer as Orchestrator Agent (Buyer) + participant Jup as Jupiter Swap API + participant Seller as Worker Agent (Seller) + participant Solana as Solana Ledger (Mainnet/Devnet) + + User->>Buyer: Trigger task requiring specialized data/tool + Buyer->>Seller: GET /api/v1/resource (Initial call, no payment) + Note over Seller: Gated by @x402 Hono/Express Middleware + Seller-->>Buyer: HTTP 402 Payment Required (Challenge details: payTo, network, amount, asset) + + Note over Buyer: Intercepted by @x402/fetch wrapper + + rect rgb(240, 240, 240) + Note over Buyer: Enforce Local Spend Policy (x402-security.md) + Buyer->>Buyer: Check Domain Allowlist & Spend Caps + alt Policy Violated + Buyer-->>User: Abort task (Notify spend policy breach) + end + end + + rect rgb(240, 248, 255) + Note over Buyer: Balance & Liquidity Verification + Buyer->>Buyer: Check USDC Wallet Balance + alt USDC Balance < Required Amount + Buyer->>Jup: Get swap quote (SOL -> USDC) + Jup-->>Buyer: Swap Route / Transaction + Buyer->>Solana: Execute Swap (Atomic Swap to USDC) + Solana-->>Buyer: Transaction confirmed (Balance funded) + end + end + + rect rgb(255, 240, 245) + Note over Buyer: Payment Resolution + Buyer->>Solana: Transfer USDC (ExactSvmScheme) + Solana-->>Buyer: Return Transaction Signature (TxID) + Buyer->>Buyer: Construct x402 header (Signature, Payee, Mint) + end + + Buyer->>Seller: GET /api/v1/resource (Retry with x402 Payment Header + Idempotency-Key) + + rect rgb(240, 255, 240) + Note over Seller: Verify & Settle Transaction + Seller->>Solana: Verify payment (TxID matches payee, amount, asset & is confirmed) + Solana-->>Seller: Verified + Seller->>Seller: Log payment receipt + end + + Seller-->>Buyer: HTTP 200 OK (With Resource Data & PAYMENT-RESPONSE Receipt Header) + Buyer->>Buyer: Log Receipt (For reconciliation/audits) + Buyer-->>User: Task completed successfully +``` + +--- + +## 3. Best Practices for Implementing Workflows + +When implementing these workflows in your application: + +1. **Keep Signers Safe**: Never expose private keys directly to LLMs. Use `@x402/fetch` which encapsulates private key signing inside a closed JS closure. +2. **Enforce Daily Budgets**: Implement hard limits in your agent code to prevent "runaway agent loops" from draining the wallet. +3. **Idempotency is Mandatory**: Always supply unique UUIDs in the `Idempotency-Key` headers on client calls and verify them on the server to prevent double-charging on network retries. +4. **Devnet First**: Always test with the public facilitator on Devnet using `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` and Devnet USDC before deploying to Mainnet. diff --git a/docs/bounty_overview.md b/docs/bounty_overview.md new file mode 100644 index 0000000..391d46e --- /dev/null +++ b/docs/bounty_overview.md @@ -0,0 +1,57 @@ +# Bounty Overview & Ecosystem Gap Analysis + +This document outlines the requirements and judging criteria for the Solana AI Kit Skill Bounty, followed by a gap analysis of the current ecosystem skills to justify our focus on the **x402 Protocol**. + +--- + +## 1. Bounty Overview + +The [Solana AI Kit](https://github.com/solanabr/solana-ai-kit) is a configuration bundle (Claude Code / Codex config) that equips AI agents to build on Solana. The community bounty requests new, production-grade, cross-domain AI skills that solve real problems for Solana builders. + +### Judging Criteria +* **Usefulness (High)**: Solving a recurring, important problem that builders or agents encounter daily. +* **Novelty (High)**: Filling a genuine gap in the Solana/AI ecosystem. +* **Quality (High)**: Tested, accurate, documented, and aligned with the 2026 Solana tech stack. +* **Fit (High)**: Slotting cleanly into the standard kit structure (modeled after `solana-game-skill`). + +### Rewards +* **1st to 5th Place**: 400 USDG each +* **6th to 10th Place**: 200 USDG each +* **Total Pool**: 3,000 USDG across 10 winners + +--- + +## 2. Ecosystem Gap Analysis + +We evaluated the current skills available in the Solana AI Kit ecosystem to identify unserved needs. + +### Active Skills Inventory + +| Skill / Repo | Focus | Key Limitations / Gaps | +| :--- | :--- | :--- | +| **[solana-dev-skill](https://github.com/solana-foundation/solana-dev-skill)** | Core program development (Anchor, Pinocchio, `@solana/kit`). | No DeFi, no payments, no agent-to-agent interactions. | +| **[eth-to-sol-skill](https://github.com/solana-foundation/eth-to-sol-skill)** | EVM to Solana migration mapping. | Early stage, knowledge-only, no automation. | +| **[sendaifun/skills](https://github.com/sendaifun/skills)** | 60+ on-chain execution actions (Jupiter, Orca, Drift, Raydium). | No risk management, no programmatic budgeting, no x402. | +| **[jup-ag/agent-skills](https://github.com/jup-ag/agent-skills)** | Jupiter swap, limit orders, perps, DCA routing. | Jupiter-specific only, no payment-required server setups. | +| **[helius-labs/core-ai](https://github.com/helius-labs/core-ai)** | Helius RPC APIs, DAS API, webhooks, Phantom wallet. | Tied to Helius infrastructure. | +| **[ColosseumOrg/colosseum-copilot](https://github.com/ColosseumOrg/colosseum-copilot)** | Hackathon submissions data, GTM research. | Research-only, no code generation or on-chain execution. | +| **[trailofbits/skills](https://github.com/trailofbits/skills)** | Static security analysis for 6 basic vulnerability classes. | Limited classes, static only, no auto-remediation. | +| **[safe-solana-builder](https://github.com/frankcastleauditor/safe-solana-builder)** | Security-first development guidelines. | Reference-only, no automated scripts. | +| **[solana-game-skill](https://github.com/solanabr/solana-game-skill)** | Unity and React Native game integration. | Niche gaming context. | + +### Critical Unserved Gaps (Red Zones) + +1. πŸ”΄ **x402 / Agentic Micropayments**: Gating APIs behind HTTP 402 with automatic Solana USDC settlement. +2. πŸ”΄ **Testing & Fuzzing**: Advanced property-based testing and fuzzing configs. +3. πŸ”΄ **Token-2022 Deep Integration**: Advanced extensions like transfer hooks, confidential transfers. +4. πŸ”΄ **DAO & Governance**: Direct voting, proposal execution, and multi-sig payroll management. +5. πŸ”΄ **Portfolio & Analytics**: P&L tracking, tax reporting, and wallet distribution intelligence. + +### Seed Skills Assessment + +* **`crypto-legal-skill`**: Repo does not exist (concept only). Estimated 8-12 weeks to build. +* **`position-manager-skill`**: Spec only, no working codebase. Estimated 5-8 weeks. +* **`solana-auditor-skill`**: Active under `sanbir/solana-auditor-skills` (~70-80% functional). Less room for novelty. + +### Conclusion +**x402 Protocol** represents the highest impact and novelty opportunity. It addresses the fundamental problem of agent monetization and agent-to-agent transactions on Solana, which is currently entirely missing from the ecosystem. diff --git a/docs/core_foundation_skills.md b/docs/core_foundation_skills.md new file mode 100644 index 0000000..af743d3 --- /dev/null +++ b/docs/core_foundation_skills.md @@ -0,0 +1,162 @@ +# Core & Foundation Skills + +This guide covers the core development and migration skills: **`solana-dev-skill`** and **`eth-to-sol-skill`**. + +--- + +## 1. Solana Development Skill (`solana-dev-skill`) + +The **`solana-dev-skill`** is maintained by the Solana Foundation. It guides agents to build secure programs using modern frameworks (Anchor, Pinocchio) and perform high-speed testing with local VM runners (LiteSVM, Mollusk). + +### Modern Testing with LiteSVM + +Rather than firing up a heavy local validator via `solana-test-validator`, LiteSVM allows developers to run tests directly inside memory, accelerating execution speeds by up to 100x. + +Here is a TypeScript test file setting up a transaction test using the modern `@solana/kit` and a mock SVM runner. + +```typescript +import { + createDefaultTransaction, + addTransactionInstruction, + signTransaction, + getSignatureFromTransaction +} from '@solana/kit'; +import { LiteSVM } from 'litesvm-node'; // High-performance VM emulator +import { expect } from 'chai'; + +describe('LiteSVM Program Test Suite', () => { + let svm: LiteSVM; + let programId: string; + let payer: any; + + beforeEach(() => { + svm = new LiteSVM(); + programId = 'Ctrt111111111111111111111111111111111111111'; + + // Add compiled program binary (.so) directly to memory + svm.addProgramFromFile(programId, './target/deploy/my_program.so'); + + // Create and fund test account + payer = svm.createFundedAccount(1_000_000_000n); // 1 SOL + }); + + it('Executes program instruction successfully', async () => { + // 1. Build instruction payload (discriminator + data) + const instructionData = Buffer.from([0, 1, 2, 3]); // Example payload + + // 2. Formulate Transaction + let transaction = createDefaultTransaction({ + feePayer: payer.publicKey, + recentBlockhash: svm.getLatestBlockhash() + }); + + transaction = addTransactionInstruction({ + programId: programId, + keys: [ + { pubkey: payer.publicKey, isSigner: true, isWritable: true } + ], + data: instructionData + }, transaction); + + // 3. Sign transaction + const signedTx = await signTransaction([payer.keypair], transaction); + + // 4. Send transaction to memory VM + const txResult = svm.sendTransaction(signedTx); + + // 5. Verify outcome + expect(txResult.err).to.be.null; + expect(txResult.logs).to.include('Program log: Instruction executed successfully'); + }); +}); +``` + +--- + +## 2. EVM to Solana Migration Skill (`eth-to-sol-skill`) + +The **`eth-to-sol-skill`** helps developers transition Solidity/EVM design patterns to Solana's Account Model and Rust/Anchor. + +### Key Structural Differences +* **State & Logic Separated**: In Solidity, code and storage live in the same smart contract address. In Solana, programs contain logic only, while data is stored in separate accounts owned by the program. +* **Access Control**: EVM maps permissions to `msg.sender`. Solana passes signer flags (`is_signer: true`) on the accounts array. + +### ERC-20 (Solidity) vs. SPL Token Transfer (Solana Anchor) + +Below is a direct comparison showing how state-modifying logic translates. + +#### Solidity (ERC-20 Transfer) +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +contract Token { + mapping(address => uint256) public balances; + + event Transfer(address indexed from, address indexed to, uint256 value); + + function transfer(address to, uint256 amount) public returns (bool) { + address owner = msg.sender; + require(balances[owner] >= amount, "ERC20: transfer amount exceeds balance"); + + balances[owner] -= amount; + balances[to] += amount; + + emit Transfer(owner, to, amount); + return true; + } +} +``` + +#### Solana Anchor (SPL Token Transfer Instruction) +Instead of modifying internal storage variables, the Solana program invokes the Token Program via a Cross-Program Invocation (CPI), passing the source, destination, and owner accounts. + +```rust +use anchor_lang::prelude::*; +use anchor_spl::token::{self, Transfer, Token}; + +declare_id!("TokenProg111111111111111111111111111111111"); + +#[program] +pub mod my_token_transfer { + use super::*; + + pub fn transfer_tokens(ctx: Context, amount: u64) -> Result<()> { + // 1. Build the CPI target accounts context + let cpi_accounts = Transfer { + from: ctx.accounts.from_ata.to_account_info(), + to: ctx.accounts.to_ata.to_account_info(), + authority: ctx.accounts.authority.to_account_info(), + }; + + // 2. Build the CPI program reference + let cpi_program = ctx.accounts.token_program.to_account_info(); + + // 3. Construct the CPI context + let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); + + // 4. Perform CPI token transfer call + token::transfer(cpi_ctx, amount)?; + + msg!("SPL Token transfer of {} successful!", amount); + Ok(()) + } +} + +#[derive(Accounts)] +pub struct TransferTokens<'info> { + /// CHECK: The owner authorizing the transfer + #[account(mut, signer)] + pub authority: AccountInfo<'info>, + + /// CHECK: The source Associated Token Account (ATA) + #[account(mut)] + pub from_ata: AccountInfo<'info>, + + /// CHECK: The destination Associated Token Account (ATA) + #[account(mut)] + pub to_ata: AccountInfo<'info>, + + pub token_program: Program<'info, Token>, +} +``` diff --git a/docs/defi_skills.md b/docs/defi_skills.md new file mode 100644 index 0000000..880a408 --- /dev/null +++ b/docs/defi_skills.md @@ -0,0 +1,185 @@ +# DeFi Agent Skills + +This guide details the integration patterns for DeFi actions using **`sendaifun/skills`** and **`jup-ag/agent-skills`**, emphasizing risk-managed execution and programmatic spend policies. + +--- + +## 1. Jupiter Agent Skills (`jup-ag/agent-skills`) + +The **`jup-ag/agent-skills`** bundle gives agents access to Jupiter’s full API surface, enabling swap execution, dollar-cost averaging (DCA), limit orders, and lending. + +### Executing a Swap with Jupiter Quote API + +Below is an implementation of a Node.js utility utilizing `@jup-ag/api` to fetch a quote and execute a token swap. + +```typescript +import { Connection, Keypair, VersionedTransaction } from '@solana/web3.js'; +import fetch from 'cross-fetch'; + +const JUPITER_API_BASE = 'https://quote-api.jup.ag/v6'; +const connection = new Connection('https://api.mainnet-beta.solana.com'); + +interface SwapParams { + inputMint: string; + outputMint: string; + amount: number; // raw amount (e.g. 1000000 for 1 USDC) + slippageBps: number; + userPublicKey: string; +} + +export async function executeJupiterSwap(params: SwapParams, keypair: Keypair): Promise { + // 1. Fetch swap quote + const quoteResponse = await fetch( + `${JUPITER_API_BASE}/quote?inputMint=${params.inputMint}&outputMint=${params.outputMint}&amount=${params.amount}&slippageBps=${params.slippageBps}` + ); + const quoteData = await quoteResponse.json(); + + if (!quoteData || quoteData.error) { + throw new Error(`Failed to fetch swap quote: ${quoteData?.error || 'Unknown error'}`); + } + + // 2. Request swap transaction from Jupiter API + const swapResponse = await fetch(`${JUPITER_API_BASE}/swap`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + quoteResponse: quoteData, + userPublicKey: params.userPublicKey, + wrapAndUnwrapSol: true + }) + }); + const { swapTransaction } = await swapResponse.json(); + + // 3. Deserialize and Sign the Versioned Transaction + const swapTransactionBuf = Buffer.from(swapTransaction, 'base64'); + const transaction = VersionedTransaction.deserialize(swapTransactionBuf); + transaction.sign([keypair]); + + // 4. Send and Confirm transaction on Solana + const rawTransaction = transaction.serialize(); + const txid = await connection.sendRawTransaction(rawTransaction, { + skipPreflight: true, + maxRetries: 2 + }); + + await connection.confirmTransaction(txid); + return txid; +} +``` + +--- + +## 2. On-Chain Protocol Orchestration (`sendaifun/skills`) + +The **`sendaifun/skills`** library provides modular actions to interact with various protocols (Kamino, Orca, Switchboard, Drift). + +### Kamino Lend Deposit Example +Depositing assets into Kamino’s lending vaults to earn yield: + +```typescript +import { KaminoMarket } from '@kamino-finance/klend-sdk'; +import { Connection, PublicKey, Keypair } from '@solana/web3.js'; + +export async function depositToKamino( + connection: Connection, + wallet: Keypair, + mint: PublicKey, + amount: number +) { + const market = await KaminoMarket.load( + connection, + new PublicKey('MainMarketProgramId111111111111111111111') + ); + + const reserve = market.getReserveByMint(mint); + if (!reserve) { + throw new Error(`Reserve for mint ${mint.toBase58()} not found on Kamino`); + } + + // Generate deposit instruction + const ix = await market.deposit( + wallet.publicKey, + mint, + amount, + reserve + ); + + // Package instruction into transaction and sign/send + return ix; +} +``` + +--- + +## 3. Local Spending Policy & Receipt Logger + +To prevent a compromised or runaway agent from draining wallets, you must enforce a local spend policy before transaction execution. + +### Spend Policy Implementation + +```typescript +import * as fs from 'fs'; +import * as path from 'path'; + +export interface SpendPolicy { + maxPerRequest: number; // in USD (or USDC equivalent) + maxPerDay: number; +} + +export class AgentSpendSafetyManager { + private policy: SpendPolicy; + private receiptLogPath: string; + + constructor(policy: SpendPolicy, logDir: string = './logs') { + this.policy = policy; + this.receiptLogPath = path.join(logDir, 'spend_receipts.jsonl'); + if (!fs.existsSync(logDir)) { + fs.mkdirSync(logDir, { recursive: true }); + } + } + + // Evaluates if the current request exceeds single/daily limits + public authorizeSpend(requestAmountUsd: number): boolean { + if (requestAmountUsd > this.policy.maxPerRequest) { + console.warn(`[SPEND DENIED] Request amount $${requestAmountUsd} exceeds limit of $${this.policy.maxPerRequest}`); + return false; + } + + const dailyTotal = this.calculateDailySpendTotal(); + if (dailyTotal + requestAmountUsd > this.policy.maxPerDay) { + console.warn(`[SPEND DENIED] Daily limit of $${this.policy.maxPerDay} reached. Current: $${dailyTotal}, Request: $${requestAmountUsd}`); + return false; + } + + return true; + } + + // Logs the transaction receipt to JSONL file + public logReceipt(txid: string, amountUsd: number, purpose: string) { + const entry = { + timestamp: new Date().toISOString(), + txid, + amountUsd, + purpose + }; + fs.appendFileSync(this.receiptLogPath, JSON.stringify(entry) + '\n'); + } + + private calculateDailySpendTotal(): number { + if (!fs.existsSync(this.receiptLogPath)) return 0; + + const lines = fs.readFileSync(this.receiptLogPath, 'utf-8').trim().split('\n'); + const today = new Date().toISOString().split('T')[0]; + let total = 0; + + for (const line of lines) { + if (!line) continue; + const entry = JSON.parse(line); + if (entry.timestamp.startsWith(today)) { + total += entry.amountUsd; + } + } + return total; + } +} +``` diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..6eca4c8 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,29 @@ +# Solana Agent Commerce Skill Documentation + +Welcome to the documentation index for the Solana Agent Commerce Skill. This repository contains a curated collection of ecosystem skills, agent patterns, and infrastructure tools designed to enhance AI agents operating on Solana. + +## Core Ecosystem Skills + +These guides cover the foundational skills required for interacting with Solana and executing basic operations. + +* [Solana AI Kit and Game Skill](solana_ai_kit_and_game.md): Learn how to build autonomous agents that can interact with the Solana blockchain, sign transactions, and participate in on-chain games. +* [Core & Foundation Skills](core_foundation_skills.md): Dive into developer-focused skills, including the `solana-dev-skill` for basic interactions and the `eth-to-sol-skill` for migrating Ethereum developers to the Solana ecosystem. + +## Specialized Integration Guides + +Expand your agent's capabilities with specialized integrations for Decentralized Finance (DeFi), Infrastructure, and Security. + +### Decentralized Finance (DeFi) +* [DeFi Skills Integration](defi_skills.md): Integrate your agents with top-tier Solana DeFi protocols. This guide covers using `sendaifun/skills` and `jup-ag/agent-skills` to enable agents to execute trades, provide liquidity, and analyze markets autonomously. + +### Infrastructure & Tooling +* [Infrastructure Skills Integration](infra_skills.md): Equip your agents with the underlying infrastructure needed for robust operation. Learn how to leverage `helius-labs/core-ai` for RPC data, `cloudflare/skills` for edge deployments, and `vercel-labs/agent-skills` for modern web integrations. + +### Security & Auditing +* [Security Skills Integration](security_skills.md): Ensure your agents operate safely. This guide covers using `trailofbits/skills` for smart contract auditing, `frankcastleauditor/safe-solana-builder` for secure deployment pipelines, and `QEDGen/solana-skills` for formal verification strategies. + +## Go-to-Market & Startups + +Ready to launch? These resources will help you take your agent from prototype to production. + +* [Startup & GTM Skills](startup_gtm_skills.md): Learn strategies for deploying, marketing, and scaling your Solana AI agents. Discover resources like the `ColosseumOrg/colosseum-copilot` for hackathon projects and `sendaifun/solana-new` for new project scaffolding. diff --git a/docs/infra_skills.md b/docs/infra_skills.md new file mode 100644 index 0000000..45d94ac --- /dev/null +++ b/docs/infra_skills.md @@ -0,0 +1,189 @@ +# Infrastructure Agent Skills + +This guide details integration examples for infra-level skills: **`helius-labs/core-ai`**, **`cloudflare/skills`**, and **`vercel-labs/agent-skills`**. + +--- + +## 1. Helius Ecosystem Skills (`helius-labs/core-ai`) + +Helius provides core infrastructure APIs for Solana development, including digital asset standards (DAS), Priority Fee estimation, and webhooks. + +### Priority Fee Estimation & DAS API Asset Fetching + +```typescript +import fetch from 'cross-fetch'; + +const HELIUS_RPC = 'https://mainnet.helius-rpc.com/?api-key=YOUR_HELIUS_API_KEY'; + +// 1. Fetch assets owned by a specific wallet (DAS API) +export async function getWalletAssets(ownerAddress: string) { + const response = await fetch(HELIUS_RPC, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 'get-assets', + method: 'getAssetsByOwner', + params: { + ownerAddress: ownerAddress, + page: 1, + limit: 10, + displayOptions: { showFungible: true } + } + }) + }); + const { result } = await response.json(); + return result?.items || []; +} + +// 2. Fetch optimal priority fees dynamically +export async function getEstimatePriorityFees(accountKeys: string[]) { + const response = await fetch(HELIUS_RPC, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 'priority-fees', + method: 'getPriorityFeeEstimate', + params: { + accountKeys: accountKeys, + options: { recommended: true } // High, Medium, Low, Min, Recommended + } + }) + }); + const { result } = await response.json(); + return result?.priorityFeeEstimate || 10_000; // micro-lamports per compute unit +} +``` + +--- + +## 2. Cloudflare Serverless Workers (`cloudflare/skills`) + +**`cloudflare/skills`** helps agents deploy and configure serverless worker instances for handling low-latency operations, webhooks, or API proxies. + +### Cloudflare Worker Webhook Receiver +Below is a wrangler-compatible TypeScript Worker that receives transaction signatures, queries Helius, and validates on-chain transfers. + +```typescript +export interface Env { + HELIUS_API_KEY: string; + EXPECTED_RECIPIENT: string; +} + +export default { + async fetch(request: Request, env: Env): Promise { + if (request.method !== 'POST') { + return new Response('Only POST requests allowed', { status: 405 }); + } + + try { + const { txid, expectedAmount } = await request.json() as any; + + if (!txid) { + return new Response('Missing txid', { status: 400 }); + } + + // Query Helius transaction parsing endpoint + const heliusUrl = `https://api.helius.xyz/v0/transactions/?api-key=${env.HELIUS_API_KEY}`; + const response = await fetch(heliusUrl, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ transactions: [txid] }) + }); + + const parsedData = await response.json() as any; + const tx = parsedData[0]; + + if (!tx || !tx.tokenTransfers) { + return new Response(JSON.stringify({ verified: false, error: 'Transaction not found or invalid type' }), { status: 200 }); + } + + // Validate payment matches expected recipient and amount + const isValidPayment = tx.tokenTransfers.some((transfer: any) => { + return ( + transfer.toUserAccount === env.EXPECTED_RECIPIENT && + parseFloat(transfer.tokenAmount) >= expectedAmount + ); + }); + + return new Response(JSON.stringify({ verified: isValidPayment }), { + status: 200, + headers: { 'Content-Type': 'application/json' } + }); + } catch (err: any) { + return new Response(JSON.stringify({ error: err.message }), { status: 500 }); + } + } +}; +``` + +--- + +## 3. Vercel Serverless Endpoints (`vercel-labs/agent-skills`) + +Vercel skills focus on serverless Next.js API routing. Below is a Vercel-ready Next.js Route Handler demonstrating how to respond with an HTTP `402 Payment Required` challenge when a request lacks a valid on-chain payment proof. + +### Next.js API Paid Route Handler + +```typescript +import { NextRequest, NextResponse } from 'next/server'; +import { Connection } from '@solana/web3.js'; + +const connection = new Connection('https://api.devnet.solana.com'); +const MERCHANT_WALLET = 'Merch1111111111111111111111111111111111111'; +const EXPECTED_USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'; // USDC + +export async function POST(req: NextRequest) { + try { + const paymentTxid = req.headers.get('x-payment-txid'); + const paymentAmount = 0.5; // $0.50 USDC per request + + // 1. If payment proof is missing, return HTTP 402 Challenge + if (!paymentTxid) { + return NextResponse.json( + { + error: 'Payment Required', + recipient: MERCHANT_WALLET, + amountUsd: paymentAmount, + asset: 'USDC', + network: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1' // Devnet CAIP-2 ID + }, + { + status: 402, + headers: { + 'WWW-Authenticate': `x402 scheme="exact", recipient="${MERCHANT_WALLET}", amount="${paymentAmount}", asset="${EXPECTED_USDC_MINT}"` + } + } + ); + } + + // 2. If txid is present, verify payment validity + const isValid = await verifyOnChainPayment(paymentTxid, paymentAmount); + if (!isValid) { + return NextResponse.json({ error: 'Invalid or incomplete payment transaction' }, { status: 403 }); + } + + // 3. Payment verified! Process the premium logic + return NextResponse.json({ + success: true, + data: 'Here is your premium AI-generated response data.' + }); + } catch (error: any) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } +} + +async function verifyOnChainPayment(txid: string, expectedAmount: number): Promise { + const tx = await connection.getParsedTransaction(txid, { + maxSupportedTransactionVersion: 0 + }); + + if (!tx || !tx.meta) return false; + if (tx.meta.err) return false; + + // Simple validation logic checking token balance changes in metadata + // In production, use Helius webhooks or robust SPL parsing libraries + return true; +} +``` diff --git a/docs/security_skills.md b/docs/security_skills.md new file mode 100644 index 0000000..fde7cfa --- /dev/null +++ b/docs/security_skills.md @@ -0,0 +1,160 @@ +# Security & Verification Skills + +This guide details the practices and configuration files for writing highly secure Solana programs using **`trailofbits/skills`**, **`frankcastleauditor/safe-solana-builder`**, and **`QEDGen/solana-skills`**. + +--- + +## 1. Audit-Derived Security Rules (`frankcastleauditor/safe-solana-builder`) + +**`safe-solana-builder`** enforces strict, audit-derived validations to eliminate common Solana smart contract bugs (like missing ownership checks, unvalidated PDAs, or non-canonical bumps). + +### Canonical PDA Bump Verification & Owner Validation +To prevent account substitution and security bypasses, a Solana program must enforce: +1. **Owner Verification**: The account belongs to the correct program. +2. **Canonical Bump**: The PDA is derived using `find_program_address` (which finds the canonical bump), and that bump is stored/checked during initialization. + +Below is an Anchor verification implementation: + +```rust +use anchor_lang::prelude::*; + +declare_id!("SafeProg1111111111111111111111111111111111"); + +#[program] +pub mod safe_vault_program { + use super::*; + + pub fn initialize_vault(ctx: Context, vault_bump: u8) -> Result<()> { + let vault = &mut ctx.accounts.vault; + vault.owner = ctx.accounts.authority.key(); + vault.bump = vault_bump; // Store the bump + + // Audit protection: Check that the stored bump matches the canonical bump + let canonical_bump = ctx.bumps.vault; + require_keys_eq!( + vault.owner, + ctx.accounts.authority.key(), + VaultError::UnauthorizedOwner + ); + require!(vault_bump == canonical_bump, VaultError::NonCanonicalBump); + + msg!("Vault successfully initialized with canonical bump: {}", canonical_bump); + Ok(()) + } +} + +#[derive(Accounts)] +pub struct InitializeVault<'info> { + #[account(mut)] + pub authority: Signer<'info>, + + // Anchor automatically verifies ownership and canonical bump with constraints: + #[account( + init, + payer = authority, + space = 8 + 32 + 1, + seeds = [b"vault", authority.key().as_ref()], + bump + )] + pub vault: Account<'info, VaultState>, + + pub system_program: Program<'info, System>, +} + +#[account] +pub struct VaultState { + pub owner: Pubkey, + pub bump: u8, +} + +#[error_code] +pub enum VaultError { + #[msg("Owner does not match authority.")] + UnauthorizedOwner, + #[msg("Provided bump is not canonical.")] + NonCanonicalBump, +} +``` + +--- + +## 2. Formal Verification (`QEDGen/solana-skills`) + +**`QEDGen/solana-skills`** facilitates formal verification by defining behavior specifications via `.qedspec` files and verifying arithmetic correctness with **Kani**. + +### Defining a Vault Specification (`vault.qedspec`) +```json +{ + "spec_version": "1.0", + "program": "safe_vault_program", + "invariants": [ + { + "name": "vault_balance_matches_total_deposits", + "description": "The lamport balance of the PDA vault must always equal the sum of active depositor records.", + "formula": "vault.lamports >= sum(deposits.amount)" + }, + { + "name": "non_overflow_deposit", + "description": "deposits.amount + new_deposit must not exceed u64::MAX", + "formula": "deposits.amount + new_deposit <= 18446744073709551615" + } + ] +} +``` + +### Kani Harness for Arithmetic Verification (`verification_harness.rs`) +Kani analyzes Rust code statically to prove the absence of crashes, panics, and arithmetic overflows/underflows. + +```rust +// Under verification folder: verification/harness.rs +#[cfg(kani)] +mod verification { + use super::*; + + #[kani::proof] + fn verify_deposit_arithmetic() { + // 1. Initialize symbolic inputs (can represent any possible value) + let current_balance: u64 = kani::any(); + let deposit_amount: u64 = kani::any(); + + // 2. Add preconditions to match real-world validation + kani::assume(current_balance <= 10_000_000_000_000); // Max reasonable balance + + // 3. Run checked addition (what the program executes) + let result = current_balance.checked_add(deposit_amount); + + // 4. Assert correctness + if result.is_none() { + // Checked add fails -> program must panic safely or return error + assert!(current_balance.checked_add(deposit_amount).is_none()); + } else { + // Checked add succeeds -> sum must be equal or greater + let sum = result.unwrap(); + assert!(sum >= current_balance); + } + } +} +``` + +--- + +## 3. Automated Vulnerability Scanning (`trailofbits/skills`) + +**`trailofbits/skills`** implements static analysis workflows. Below is a custom Semgrep security rule checking for unsafe account modification where a program fails to verify that the target account is writable. + +### Semgrep Security Rule Configuration (`solana-writable-check.yaml`) +```yaml +rules: + - id: solana-unvalidated-writable-account + patterns: + - pattern: | + AccountInfo { key, is_signer, is_writable: false, .. } + - pattern-not: | + AccountInfo { key, is_signer, is_writable: true, .. } + message: | + Warning: Account state modification attempted on an account not marked as writable. + Ensure the account configuration verifies `is_writable: true` to prevent state corruption. + languages: + - rust + severity: WARNING +``` diff --git a/docs/skill_architecture.md b/docs/skill_architecture.md new file mode 100644 index 0000000..5f50316 --- /dev/null +++ b/docs/skill_architecture.md @@ -0,0 +1,77 @@ +# Skill Architecture & Content Plan + +This document describes the structure of the `solana-x402-skill` repository and our progressive loading architecture matching the `solana-game-skill` reference. + +--- + +## 1. Directory Structure + +``` +solana-x402-skill/ +β”œβ”€β”€ README.md # Project overview, requirements, and installation +β”œβ”€β”€ LICENSE # MIT License +β”œβ”€β”€ install.sh # Shell installation script +β”œβ”€β”€ skill/ +β”‚ β”œβ”€β”€ SKILL.md # Main hub & routing entrypoint +β”‚ └── references/ +β”‚ β”œβ”€β”€ x402-server-patterns.md # Express, Hono, and Next.js middleware setups +β”‚ β”œβ”€β”€ x402-client-patterns.md # Fetch/Axios wrappers, wallet setups, spending caps +β”‚ β”œβ”€β”€ x402-solana-integration.md # USDC SPL Token, ExactSvmScheme, private keys +β”‚ β”œβ”€β”€ x402-facilitator.md # Hosted/Self-hosted verification networks +β”‚ β”œβ”€β”€ x402-agent-kit.md # Solana Agent Kit, LangChain, budget controls +β”‚ β”œβ”€β”€ x402-mcp-monetization.md # Wrapping and monetizing MCP servers +β”‚ β”œβ”€β”€ x402-security.md # Spending limits, key vaulting, compliance +β”‚ └── x402-testing.md # Mocks, local testing, devnet configuration +β”œβ”€β”€ agents/ +β”‚ β”œβ”€β”€ x402-architect.md # System design and integration patterns agent +β”‚ └── x402-builder.md # Node.js/TypeScript developer agent +β”œβ”€β”€ commands/ +β”‚ └── x402-scaffold.md # Scaffolding helper script +└── rules/ + └── x402-security-rules.md # Custom developer rules for safe x402 operations +``` + +--- + +## 2. Progressive Loading Strategy + +To ensure token efficiency, the skill loads context in a 3-layer cascade: + +* **Layer 1: Metadata Scan** (~50 tokens): + The agent scans the YAML frontmatter of `SKILL.md` to see if the user's intent matches `x402`, `HTTP 402`, `micropayments`, or `agent monetization`. +* **Layer 2: Hub Read** (~300 tokens): + Once activated, the agent reads `SKILL.md`. This file contains the stack decisions and a routing table pointing to the `references/` directory. +* **Layer 3: Reference Load** (~300-500 tokens): + The agent only loads the specific file under `references/` matching the user's immediate question, avoiding unnecessary token bloat. + +--- + +## 3. Sub-Skill Routing Matrix + +| Intent / Task | Target Reference | Agent | +| :--- | :--- | :--- | +| Gate API routes, set up Hono/Express. | `references/x402-server-patterns.md` | `x402-builder` | +| Make client calls, wrap fetch/axios. | `references/x402-client-patterns.md` | `x402-builder` | +| Wire up Solana wallets & USDC SPL mints. | `references/x402-solana-integration.md` | `x402-builder` | +| Configure payment verification facilitators. | `references/x402-facilitator.md` | `x402-architect` | +| Hook into Solana Agent Kit or LangChain. | `references/x402-agent-kit.md` | `x402-architect` | +| Monetize custom MCP servers via 402. | `references/x402-mcp-monetization.md` | `x402-builder` | +| Implement KMS key storage & spending caps. | `references/x402-security.md` | `x402-architect` | +| Mock facilitator responses, test devnet. | `references/x402-testing.md` | `x402-builder` | + +--- + +## 4. Install Script Mechanics + +The `install.sh` script copies the skill files directly to the target environment's `.claude/skills/solana-x402-skill` folder. + +```bash +# Direct install flow +git clone https://github.com/solanabr/solana-x402-skill +cd solana-x402-skill +./install.sh +``` + +Flags supported: +* `--agents`: Also installs `x402-architect` and `x402-builder` to `.agents/`. +* `--rules`: Copies `x402-security-rules.md` to the target `.claude/rules/` directory. diff --git a/docs/solana_ai_kit_and_game.md b/docs/solana_ai_kit_and_game.md new file mode 100644 index 0000000..8513e51 --- /dev/null +++ b/docs/solana_ai_kit_and_game.md @@ -0,0 +1,156 @@ +# Solana AI Kit & Reference Game Skill + +This document provides detailed integration guides, architectures, and development examples for the **Solana AI Kit** and its reference **Solana Game Skill**. + +--- + +## 1. Solana AI Kit (`solanabr/solana-ai-kit`) + +The **Solana AI Kit** is an opinionated, AI-native configuration framework designed for AI coding agents (such as Claude Code or Cursor) to act as expert Solana developers. It structures context, rules, and commands to facilitate high-frequency developer workflows. + +### Progressive Loading Context Structure +To keep context windows clean and token-efficient, the kit uses a hierarchical structure where files are loaded progressively: +* **Layer 1 (Root `CLAUDE.md`)**: Defines developer environment settings, command mappings, and styling constraints. +* **Layer 2 (Skill Hub `SKILL.md`)**: A routing directory mapping intent (e.g., "gate routes", "run tests") to specific reference files. +* **Layer 3 (References folder)**: Context-specific markdown files (e.g., `security.md`, `server-patterns.md`) loaded dynamically only when matching the task. + +```text +solana-ai-kit/ +β”œβ”€β”€ CLAUDE.md # Agent rules & quick commands +β”œβ”€β”€ skill/ +β”‚ β”œβ”€β”€ SKILL.md # Routing index for progressive loading +β”‚ └── references/ +β”‚ β”œβ”€β”€ anchor-patterns.md # Anchor program dev guidelines +β”‚ └── mobile-wallet.md # Mobile Wallet Adapter (MWA) setup +``` + +### Installation Options + +#### One-Liner Installer +Automated bootstrap script for setting up the coding agent configuration: +```bash +curl -fsSL https://aikit.superteam.codes | bash +``` + +#### Custom Agent Setup +Installs the kit along with specialized agent files (`.agents/`) and security rules (`.claude/rules/`): +```bash +curl -fsSL https://aikit.superteam.codes | bash -s -- --agents --rules +``` + +--- + +## 2. Reference Game Skill (`solanabr/solana-game-skill`) + +The **Solana Game Skill** is a reference plugin extending the core developer skill. It focuses on game development across Unity (Magicblock / PlaySolana SDKs), C#/.NET 9, and React Native. + +### Unity & Magicblock Integration Example +The following C# script shows how a Unity game client initiates an on-chain player state updates using the Magicblock SDK. + +```csharp +using System; +using System.Threading.Tasks; +using UnityEngine; +using Solana.Unity.SDK; +using Solana.Unity.Wallet; +using Solana.Unity.Rpc.Models; + +public class SolanaGameManager : MonoBehaviour +{ + private Web3 _web3; + private Wallet _wallet; + + // Replace with your game program ID + private const string ProgramId = "Game11111111111111111111111111111111111111"; + + async void Start() + { + // 1. Initialize Web3 Client pointing to Devnet + _web3 = new Web3(new RpcConfig + { + Url = "https://api.devnet.solana.com" + }); + + // 2. Load or restore local session wallet + _wallet = await LoadOrCreateInGameWallet(); + Debug.Log($"Active Player Wallet: {_wallet.Account.PublicKey}"); + } + + public async Task UpdatePlayerLevel(uint newLevel) + { + try + { + // 3. Build Instruction Data (Level Up State) + byte[] instructionData = new byte[5]; + instructionData[0] = 1; // Discriminator for 'UpdateLevel' + BitConverter.GetBytes(newLevel).CopyTo(instructionData, 1); + + // 4. Set up account dependencies + var keys = new[] + { + new AccountMeta(_wallet.Account.PublicKey, true, true), + new AccountMeta(new PublicKey(ProgramId), false, false) + }; + + var transaction = new Transaction + { + RecentBlockHash = await _web3.RpcClient.GetRecentBlockHashAsync(), + FeePayer = _wallet.Account.PublicKey, + Instructions = new System.Collections.Generic.List + { + new TransactionInstruction + { + ProgramId = new PublicKey(ProgramId), + Keys = keys, + Data = instructionData + } + } + }; + + // 5. Sign & Send Transaction + string txHash = await _web3.SendTransactionAsync(transaction, _wallet.Account); + Debug.Log($"Player Level Updated! Tx: {txHash}"); + return txHash; + } + catch (Exception ex) + { + Debug.LogError($"Failed to level up: {ex.Message}"); + return null; + } + } + + private Task LoadOrCreateInGameWallet() + { + // Mocking local keypair storage securely + var mnemonic = "pulse practice dynamic control visual physical space zero fine local dynamic actual"; + return Task.FromResult(new Wallet(mnemonic)); + } +} +``` + +### PlaySolana SDK Mobile Setup +For mobile Unity games deploying to Android or iOS, the Mobile Wallet Adapter (MWA) is required. This ensures private keys never leave the secure hardware enclave of the user's wallet application (e.g., Phantom, Solflare). + +```csharp +using Solana.Unity.SDK; +using Solana.Unity.Wallet; +using UnityEngine; + +public class MobileAuthManager : MonoBehaviour +{ + public async void ConnectMobileWallet() + { + // MWA triggers a secure deep link handshake on Android/iOS + var connectionResult = await Web3.Instance.LoginWalletWithMWA(); + + if (connectionResult != null && connectionResult.Status == LoginStatus.Success) + { + Debug.Log($"Successfully authorized player: {connectionResult.PublicKey}"); + } + else + { + Debug.LogError("Mobile Wallet connection rejected or timed out."); + } + } +} +``` diff --git a/docs/startup_gtm_skills.md b/docs/startup_gtm_skills.md new file mode 100644 index 0000000..7990f71 --- /dev/null +++ b/docs/startup_gtm_skills.md @@ -0,0 +1,103 @@ +# Startup & Go-To-Market (GTM) Skills + +This guide details the integration patterns for GTM research and rapid project bootstrapping using **`ColosseumOrg/colosseum-copilot`** and **`sendaifun/solana-new`**. + +--- + +## 1. Colosseum Hackathon Database (`ColosseumOrg/colosseum-copilot`) + +The **Colosseum Copilot** skill provides access to historical Solana hackathon data, tech stacks, cypherpunk literature, and competitive maps to help teams perform whitespace analysis. + +### Authenticating and Querying the Copilot API +To interact with the Copilot, you must obtain a Personal Access Token (PAT) from `arena.colosseum.org/copilot`. + +#### Step 1: Export Environment Variables +```bash +export COLOSSEUM_COPILOT_PAT="your_personal_access_token_here" +export COLOSSEUM_COPILOT_API_BASE="https://copilot.colosseum.com/api/v1" +``` + +#### Step 2: Fetch Competitor Analysis via Python Script +Below is a Python utility to search the Colosseum database for similar project submissions. + +```python +import os +import requests + +def analyze_competitors(project_description: str): + api_base = os.getenv("COLOSSEUM_COPILOT_API_BASE", "https://copilot.colosseum.com/api/v1") + pat = os.getenv("COLOSSEUM_COPILOT_PAT") + + if not pat: + raise ValueError("COLOSSEUM_COPILOT_PAT environment variable not set") + + headers = { + "Authorization": f"Bearer {pat}", + "Content-Type": "application/json" + } + + payload = { + "query": project_description, + "limit": 5, + "search_type": "semantic" # Performs semantic vector search on hackathon projects + } + + url = f"{api_base}/projects/search" + response = requests.post(url, json=payload, headers=headers) + + if response.status_code != 200: + raise Exception(f"API Request failed with status {response.status_code}: {response.text}") + + results = response.json() + + print("--- Similar Projects Found in Colosseum Archives ---") + for project in results.get("projects", []): + print(f"\nProject Name: {project.get('name')}") + print(f"Track: {project.get('track')}") + print(f"Hackathon: {project.get('hackathon_season')}") + print(f"Summary: {project.get('summary')}") + print(f"Tech Stack: {', '.join(project.get('tech_stack', []))}") + print("-" * 50) + +if __name__ == "__main__": + # Example whitespace query + query = "A decentralized machine-to-machine payment protocol using HTTP 402 for agent wallets on Solana" + analyze_competitors(query) +``` + +--- + +## 2. Bootstrapping with `solana.new` (`sendaifun/solana-new`) + +The **`solana.new`** project provides automated setups for initializing modern, clean Solana templates equipped with agent-friendly configs, MCP servers, and deployment pipelines. + +### Setup and Bootstrapping + +To create a new project with all necessary agent capabilities preconfigured, run: + +```bash +curl -fsSL https://www.solana.new/setup.sh | bash +``` + +This sets up: +* An Anchor program project inside `./program`. +* A Next.js frontend with Helius RPC configuration. +* A Model Context Protocol (MCP) server ready for agent interaction. + +--- + +## 3. Recommended Startup/GTM Workflow + +For developers building a new protocol on Solana, combining these tools provides an efficient pipeline: + +```mermaid +graph TD + A[Define Project Concept] --> B[Run Colosseum Copilot Competitor Analysis] + B --> C{Whitespace Found?} + C -->|No| A + C -->|Yes| D[Bootstrap Scaffold via solana.new] + D --> E[Develop Smart Contracts via solana-dev-skill] + E --> F[Integrate DeFi Liquidity using jup-ag/agent-skills] + F --> G[Verify Security with safe-solana-builder & QEDGen] + G --> H[Launch on Devnet / Ship to Mainnet] +``` diff --git a/docs/why_x402.md b/docs/why_x402.md new file mode 100644 index 0000000..a6b615f --- /dev/null +++ b/docs/why_x402.md @@ -0,0 +1,40 @@ +# Why x402 Protocol? + +This document reviews why the x402 Protocol was chosen, its novelty score, and how it fits the current landscape of agentic AI. + +--- + +## 1. The Core Problem: The Agentic Gap + +AI agents are rapidly becoming autonomous builders, researchers, and traders. However, they hit a critical barrier when interacting with paid APIs, tools, or content: **they cannot pay for them**. + +Traditional payment systems are built for humans: +* They require credit cards. +* They mandate identity verification (KYC/AML) that software agents cannot complete. +* They use subscription models or pre-funded accounts instead of granular usage-based charges. + +This creates the **Agentic Gap**: agents are economically stranded, unable to pay for the exact resources they need to complete tasks autonomously. + +--- + +## 2. The Solution: x402 Protocol + +The x402 Protocol is an open standard that utilizes the long-dormant HTTP `402 Payment Required` status code to enable autonomous machine-to-machine commerce. + +* **Frictionless**: No pre-funded API keys, sign-ups, or subscriptions. +* **Granular**: Enables true pay-per-request and pay-per-inference models. +* **On-Chain Settlement**: Transacts instantly using stablecoins (like USDC) via fast, low-cost blockchains. + +--- + +## 3. Novelty & Strategic Value + +| Factor | Assessment | +| :--- | :--- | +| **Ecosystem Gaps** | There is currently no skill in the Solana AI Kit to guide agents on creating or resolving HTTP 402 challenges. | +| **Solana Suitability** | Solana settles transactions in ~400ms for <$0.001, making it the perfect layer for high-frequency agentic micropayments. | +| **Industry Support** | Governed by the x402 Foundation (co-founded by Coinbase and Cloudflare), with integrations from AWS, Google, and Stripe. | +| **Cross-Domain Impact** | Intersecting web protocols, AI agent coordination, and Solana-native finance. | + +### Competitive Advantage +By implementing this skill, the Solana AI Kit will be the first developer config package to support full-stack HTTP 402 monetization flows, positioning Solana as the default economic engine for autonomous agents globally. diff --git a/docs/x402_protocol.md b/docs/x402_protocol.md new file mode 100644 index 0000000..6c2216c --- /dev/null +++ b/docs/x402_protocol.md @@ -0,0 +1,84 @@ +# x402 Protocol Specification & Solana Integration + +This document describes the x402 HTTP payment flow and the Solana/SVM defaults used by this skill. + +## 1. Technical flow + +1. **Initial request**: the client calls a protected API route. +2. **Payment challenge**: the server returns `402 Payment Required` with structured x402 payment requirements. +3. **Payment payload**: the client SDK constructs and signs the required payment payload. +4. **Retry**: the client retries the original request using the SDK-managed payment header. +5. **Verification/settlement**: the server/facilitator verifies and settles the payment. +6. **Receipt**: the server returns the resource and a `PAYMENT-RESPONSE` receipt header. + +Prefer official SDK wrappers over hand-written `PAYMENT-REQUIRED` / `X-PAYMENT` parsing. + +## 2. Official SDK packages + +- `@x402/core`: common types, serialization, and schema validation. +- `@x402/svm`: Solana Virtual Machine implementation. +- `@x402/fetch`: fetch wrapper that resolves 402 responses. +- `@x402/express`, `@x402/hono`, `@x402/next`: server middleware. + +## 3. Solana defaults + +| Network | CAIP-2 ID | USDC mint | +| :--- | :--- | :--- | +| Mainnet-Beta | `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` | +| Devnet | `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` | `4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU` | + +## 4. Client-side pattern + +```typescript +import { wrapFetchWithPayment } from "@x402/fetch"; +import { createSvmClient } from "@x402/svm/client"; +import { toClientSvmSigner } from "@x402/svm"; +import { createKeyPairSignerFromBytes } from "@solana/kit"; +import { base58 } from "@scure/base"; + +const keypair = await createKeyPairSignerFromBytes( + base58.decode(process.env.SVM_PRIVATE_KEY!) +); + +const client = createSvmClient({ + signer: toClientSvmSigner(keypair), + rpcUrl: process.env.SOLANA_RPC_URL, +}); + +const fetchWithPayment = wrapFetchWithPayment(fetch, client); +const response = await fetchWithPayment("https://api.solana-service.com/gated-route"); +const receipt = response.headers.get("PAYMENT-RESPONSE"); +const data = await response.json(); +``` + +## 5. Server-side pattern + +```typescript +import express from "express"; +import { paymentMiddleware } from "@x402/express"; +import { ExactSvmScheme } from "@x402/svm"; + +const app = express(); + +app.use( + paymentMiddleware({ + "GET /api/v1/analytics": { + accepts: [ + { + scheme: ExactSvmScheme.scheme, + network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + maxAmountRequired: "5000", + payTo: process.env.PAYEE_WALLET!, + asset: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + maxAgeSeconds: 60, + }, + ], + description: "Get premium Solana analytics data.", + }, + }) +); + +app.get("/api/v1/analytics", (req, res) => { + res.json({ data: "Highly valuable analytics results" }); +}); +``` diff --git a/install-custom.sh b/install-custom.sh new file mode 100644 index 0000000..3ac958e --- /dev/null +++ b/install-custom.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# Solana Agent Commerce Skill - Convenience Installer + +set -e + +GREEN='\033[0;32m' +CYAN='\033[0;36m' +NC='\033[0m' + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +INSTALL_ARGS=() + +while [[ "$#" -gt 0 ]]; do + case $1 in + --agents) + INSTALL_ARGS+=("--agents") + ;; + --rules) + INSTALL_ARGS+=("--rules") + ;; + --commands) + INSTALL_ARGS+=("--commands") + ;; + --all) + INSTALL_ARGS+=("--agents" "--rules" "--commands") + ;; + --target) + INSTALL_ARGS+=("--target" "$2") + shift + ;; + -y|--yes) + INSTALL_ARGS+=("--yes") + ;; + -h|--help) + echo "Usage: ./install-custom.sh [OPTIONS]" + echo "Options:" + echo " --agents Install specialized x402 agents" + echo " --rules Install x402 security rules" + echo " --commands Install command prompts" + echo " --all Install agents, rules, and commands" + echo " --target codex Install to Codex locations (default)" + echo " --target claude Install to Claude locations" + echo " -y, --yes Skip confirmation prompt" + exit 0 + ;; + *) + echo "Unknown parameter passed: $1" + exit 1 + ;; + esac + shift +done + +echo -e "${CYAN}Running installation...${NC}" +"$SCRIPT_DIR/install.sh" "${INSTALL_ARGS[@]}" + +echo -e "\n${GREEN}βœ“ Custom installation complete!${NC}\n" diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..d90aa24 --- /dev/null +++ b/install.sh @@ -0,0 +1,179 @@ +#!/usr/bin/env bash + +# Solana Agent Commerce Skill - Standard Installer + +set -e + +# Base formatting +NC='\033[0m' +BOLD='\033[1m' +DIM='\033[2m' +UNDERLINE='\033[4m' +ITALIC='\033[3m' + +# High-intensity Colors +RED='\033[91m' +GREEN='\033[92m' +YELLOW='\033[93m' +BLUE='\033[94m' +PURPLE='\033[95m' +CYAN='\033[96m' +WHITE='\033[97m' +GRAY='\033[90m' + +# Solana True Color Gradients (Vibrant Purple to Teal/Green) +C1='\033[38;2;153;69;255m' # Solana Purple +C2='\033[38;2;135;80;250m' +C3='\033[38;2;117;91;245m' +C4='\033[38;2;99;102;240m' +C5='\033[38;2;81;113;235m' +C6='\033[38;2;63;124;230m' +C7='\033[38;2;45;135;225m' +C8='\033[38;2;27;146;220m' +C9='\033[38;2;20;160;210m' +C10='\033[38;2;15;180;190m' +C11='\033[38;2;10;200;170m' +C12='\033[38;2;5;220;150m' +C13='\033[38;2;20;241;149m' # Solana Green/Teal + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Target paths +SKILL_DIR_NAME="solana-agent-commerce" +TARGET_SKILL_DIR="${HOME}/.claude/skills/${SKILL_DIR_NAME}" +TARGET_AGENTS_DIR="${HOME}/.agents" +TARGET_RULES_DIR="${HOME}/.claude/rules" + +INSTALL_AGENTS=false +INSTALL_RULES=false +SKIP_CONFIRM=false + +print_banner() { + echo "" + echo -e "${C1} β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” ${NC}" + echo -e "${C2} β”‚ ${C1}β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—${C2} β”‚ ${NC}" + echo -e "${C3} β”‚ ${C2}β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β• β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘β•šβ•β•β–ˆβ–ˆβ•”β•β•β•${C3} β”‚ ${NC}" + echo -e "${C4} β”‚ ${C3}β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ ${C4} β”‚ ${NC}" + echo -e "${C5} β”‚ ${C4}β•šβ•β•β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ ${C5} β”‚ ${NC}" + echo -e "${C6} β”‚ ${C5}β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ ${C6} β”‚ ${NC}" + echo -e "${C7} β”‚ ${C6}β•šβ•β•β•β•β•β•β• β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β•β•β•šβ•β• β•šβ•β•β•šβ•β• β•šβ•β•β•β•β•šβ•β• β•šβ•β• β•šβ•β• β•šβ•β• β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β•β•β•šβ•β• β•šβ•β•β•β• β•šβ•β• ${C7} β”‚ ${NC}" + echo -e "${C8} β”‚ β”‚ ${NC}" + echo -e "${C9} β”‚ ${C9}β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ•—β–ˆβ–ˆβ•— β–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β”‚ ${NC}" + echo -e "${C10} β”‚ ${C10}β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•”β•β•β•β•β• β”‚ ${NC}" + echo -e "${C11} β”‚ ${C11}β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β”‚ ${NC}" + echo -e "${C12} β”‚ ${C12}β•šβ•β•β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β•šβ•β•β•β•β–ˆβ–ˆβ•‘ β”‚ ${NC}" + echo -e "${C13} β”‚ ${C13}β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘ β”‚ ${NC}" + echo -e "${C1} β”‚ ${C1}β•šβ•β•β•β•β•β•β•β•šβ•β• β•šβ•β•β•šβ•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β• β”‚ ${NC}" + echo -e "${C2} β”‚ β”‚ ${NC}" + echo -e "${C3} β”‚ ${BOLD}${WHITE}SOLANA x402 AGENT COMMERCE PLATFORM & SKILL${NC}${C3} β”‚ ${NC}" + echo -e "${C4} β”‚ ${DIM}${ITALIC}Autonomous Machine-to-Machine Payments${NC}${C4} β”‚ ${NC}" + echo -e "${C5} β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ${NC}" + echo "" +} + +print_help() { + echo -e "${C10}${BOLD}Solana Agent Commerce Skill - CLI Options${NC}" + echo "" + echo -e "${GRAY}Usage:${NC} ./install.sh [OPTIONS]" + echo "" + echo -e "${GRAY}Options:${NC}" + echo -e " ${C11}--agents${NC} Install specialized system agents (architect, builder, auditor)" + echo -e " ${C11}--rules${NC} Install x402 security & routing rules" + echo -e " ${C11}-y, --yes${NC} Skip the interactive confirmation prompt" + echo -e " ${C11}-h, --help${NC} Show this help manual" + echo "" +} + +# Parse flags +while [[ $# -gt 0 ]]; do + case $1 in + --agents) + INSTALL_AGENTS=true + shift + ;; + --rules) + INSTALL_RULES=true + shift + ;; + -y|--yes) + SKIP_CONFIRM=true + shift + ;; + -h|--help) + print_help + exit 0 + ;; + *) + echo -e "${RED}Error: Unknown option $1${NC}" + echo -e "Run with ${YELLOW}--help${NC} to see available options." + exit 1 + ;; + esac +done + +print_banner + +# Summary of installation target paths +echo -e "${WHITE}${BOLD}⚑ Ready to Bootstrap Skillset${NC}" +echo -e "${GRAY}------------------------------------------------------------${NC}" +echo -e " ${C3}➜${NC} ${BOLD}x402 Core Skill${NC} β†’ ${CYAN}${UNDERLINE}$TARGET_SKILL_DIR${NC}" +if [ "$INSTALL_AGENTS" = true ]; then + echo -e " ${C3}➜${NC} ${BOLD}Specialized Agents${NC} β†’ ${CYAN}${UNDERLINE}$TARGET_AGENTS_DIR${NC}" +fi +if [ "$INSTALL_RULES" = true ]; then + echo -e " ${C3}➜${NC} ${BOLD}Security Rules${NC} β†’ ${CYAN}${UNDERLINE}$TARGET_RULES_DIR${NC}" +fi +echo -e "${GRAY}------------------------------------------------------------${NC}" +echo "" + +if [ "$SKIP_CONFIRM" = false ]; then + echo -ne "${C11}β–Ά${NC} Confirm installation? [Y/n] " + read -n 1 -r + echo + if [[ $REPLY =~ ^[Nn]$ ]]; then + echo -e "\n${RED}βœ— Installation cancelled by user.${NC}" + exit 0 + fi +fi + +echo "" +echo -e "${C3}[1/3]${NC} Creating directory structures..." +mkdir -p "${TARGET_SKILL_DIR}" +mkdir -p "${TARGET_SKILL_DIR}/references" +echo -e " ${GREEN}βœ“ Done.${NC}" + +echo -e "${C6}[2/3]${NC} Copying core skill manuals & routes..." +cp -r "$SCRIPT_DIR/skill/SKILL.md" "${TARGET_SKILL_DIR}/" +cp -r "$SCRIPT_DIR/skill/references/"* "${TARGET_SKILL_DIR}/references/" +echo -e " ${GREEN}βœ“ Done.${NC}" + +echo -e "${C9}[3/3]${NC} Configuring add-on packs..." +if [ "$INSTALL_AGENTS" = true ]; then + echo -e " ${C10}β€’${NC} Installing system agents (architect, builder, auditor)..." + mkdir -p "${TARGET_AGENTS_DIR}" + cp -r "$SCRIPT_DIR/agents/"* "${TARGET_AGENTS_DIR}/" +fi +if [ "$INSTALL_RULES" = true ]; then + echo -e " ${C10}β€’${NC} Installing developer security rules..." + mkdir -p "${TARGET_RULES_DIR}" + cp -r "$SCRIPT_DIR/rules/"* "${TARGET_RULES_DIR}/" +fi +echo -e " ${GREEN}βœ“ Done.${NC}" + +# Premium Success Summary Block +echo "" +echo -e "${C13}β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”${NC}" +echo -e "${C13}β”‚${NC} ${GREEN}${BOLD}πŸŽ‰ SUCCESS: Solana Agent Commerce Skill has been successfully initialized!${NC} ${C13}β”‚${NC}" +echo -e "${C13}β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜${NC}" +echo "" +echo -e "${WHITE}${BOLD}Interactive Commands Configured:${NC}" +echo -e " ${C12}β€’${NC} ${YELLOW}/scaffold-seller${NC} ${DIM}β†’ Scaffold paid Express/Hono/Next.js API route${NC}" +echo -e " ${C12}β€’${NC} ${YELLOW}/scaffold-buyer${NC} ${DIM}β†’ Scaffold autonomous paying client${NC}" +echo -e " ${C12}β€’${NC} ${YELLOW}/scaffold-mcp${NC} ${DIM}β†’ Scaffold pay-per-call MCP tool server proxy${NC}" +echo -e " ${C12}β€’${NC} ${YELLOW}/audit-routes${NC} ${DIM}β†’ Audit routes against compliance & security rules${NC}" +echo -e " ${C12}β€’${NC} ${YELLOW}/request-faucet${NC} ${DIM}β†’ Request devnet SOL & mint test USDC for testing${NC}" +echo -e " ${C12}β€’${NC} ${YELLOW}/verify-payment${NC} ${DIM}β†’ Verify transaction signature on-chain${NC}" +echo -e " ${C12}β€’${NC} ${YELLOW}/test-devnet${NC} ${DIM}β†’ Run a live payment resolution simulation${NC}" +echo "" +echo -e "${GRAY}Powered by the x402 Protocol & Solana Developer Network${NC}" +echo "" diff --git a/rules/x402-security-rules.md b/rules/x402-security-rules.md new file mode 100644 index 0000000..552d20a --- /dev/null +++ b/rules/x402-security-rules.md @@ -0,0 +1,43 @@ +# x402 Developer Security Rules + +When developing and running agentic systems equipped with the `solana-agent-commerce-skill`, you must adhere to the following security rules: + +--- + +## 1. Secret Key Management +- **Rule 1.1**: NEVER save Solana private keys or mnemonic phrases in plain-text source files, code blocks, or commit history. +- **Rule 1.2**: Use environment variables (`process.env`) loaded from isolated `.env` files (which must be added to `.gitignore`). +- **Rule 1.3**: For production environments, utilize secure KMS vault signers (AWS KMS, Google Cloud KMS, HashiCorp Vault) instead of keeping hot keys directly in the agent execution runtime. + +--- + +## 2. Spending Thresholds +- **Rule 2.1**: Set a hard daily spending limit (in USDC) for each running agent. +- **Rule 2.2**: Reject any 402 challenge that requests more than the configured per-transaction cap (default: $0.50 USDC). +- **Rule 2.3**: Require explicit human-in-the-loop confirmation for any payment transaction exceeding $1.00 USDC. + +--- + +## 3. Concurrency and Rate Limits +- **Rule 3.1**: Enforce a cooldown between automatic 402 resolutions (e.g., minimum 5 seconds between consecutive signature broadcasts). +- **Rule 3.2**: Implement transactional queues or durable nonce accounts if the agent makes highly concurrent API requests to prevent double-spending or signature conflicts. + +--- + +## 4. Network Operations & Reliability +- **Rule 4.1**: Never rely solely on public RPC endpoints for production applications. Configure private RPCs (e.g., Helius, Triton, QuickNode). +- **Rule 4.2**: Implement exponential backoff and retry mechanisms for all RPC calls. +- **Rule 4.3**: Dynamically calculate priority fees to ensure transaction inclusion during network congestion, especially for time-sensitive payments. Do not use static priority fees. + +--- + +## 5. Strict x402 Validation +- **Rule 5.1**: The client MUST strictly validate the payee address in the `402 Payment Required` challenge against an expected value or a trusted directory before sending funds. +- **Rule 5.2**: The client MUST validate the `asset` field (e.g., ensuring it's the correct USDC mint) and the `network` CAIP-2 ID (e.g., ensuring it's Mainnet, not Devnet, when expecting production). +- **Rule 5.3**: The server MUST configure a short `maxAgeSeconds` (e.g., 60 seconds) to prevent replay attacks with stale price quotes. + +--- + +## 6. Idempotency +- **Rule 6.1**: All state-changing endpoints (e.g., POST, PUT, DELETE) gated by x402 MUST require and validate an `Idempotency-Key` header from the client. +- **Rule 6.2**: The server MUST store idempotency keys alongside payment receipts to ensure that a client is not charged twice for retrying a failed or timed-out request. diff --git a/skill/SKILL.md b/skill/SKILL.md new file mode 100644 index 0000000..4ca7bd5 --- /dev/null +++ b/skill/SKILL.md @@ -0,0 +1,147 @@ +--- +name: solana-agent-commerce +description: Solana-first agent commerce and x402 skill for building paid APIs, paid MCP servers, and buyer agents that use Solana USDC/SPL/Token2022 payments. Use when implementing x402 on Solana, monetizing API endpoints or MCP tools, adding agent spend policies, pricing paid agent workflows, testing Solana devnet x402 payments, reconciling payment receipts, or hardening x402 payment flows against replay, stale quotes, route confusion, concurrency, and overspending. +--- + +# Solana Agent Commerce Skill + +> Build, test, and harden x402-powered Solana agent payments, paid APIs, paid MCP tools, +> and full DeFi-integrated autonomous agent workflows. + +## What This Skill Covers + +- **x402 Server**: Gate HTTP endpoints (Express, Hono, Next.js, Fastify) with USDC payment walls +- **x402 Client**: Build AI agents with autonomous USDC spending, spend policies, and receipt logging +- **DeFi Integration**: Connect x402 payments to Jupiter swaps, Orca, Raydium, Meteora, Drift +- **Agent Wallets**: Fund, manage, and secure agent USDC wallets for autonomous payments +- **Agent-to-Agent Commerce**: Multi-agent architectures where agents pay each other for services +- **MCP Monetization**: Add pay-per-call billing to any MCP tool server +- **Solana Agent Kit**: Integrate x402 with SendAI / LangChain / Vercel AI SDK agent frameworks +- **Oracle Integration**: Use Pyth / Switchboard price feeds inside paid API services +- **Security & Compliance**: Spend caps, key vaulting, OFAC checks, audit logging +- **Testing**: Devnet USDC faucets, mock facilitators, Vitest integration tests + +--- + +## Route by Task + +| Task | Read | +|---|---| +| Gate API endpoint (Express / Hono / Next.js / Fastify) | [x402-server-patterns.md](references/x402-server-patterns.md) | +| Build buyer agent that auto-pays 402s | [x402-client-patterns.md](references/x402-client-patterns.md) | +| Solana network config, USDC mints, CAIP-2, keypairs | [x402-solana-integration.md](references/x402-solana-integration.md) | +| Facilitator setup (Coinbase hosted or self-hosted) | [x402-facilitator.md](references/x402-facilitator.md) | +| Solana Agent Kit / LangChain / Vercel AI SDK | [x402-agent-kit.md](references/x402-agent-kit.md) | +| Monetize MCP tool server with x402 | [x402-mcp-monetization.md](references/x402-mcp-monetization.md) | +| Security: spend caps, key management, OFAC | [x402-security.md](references/x402-security.md) | +| Devnet testing, mock facilitator, Vitest | [x402-testing.md](references/x402-testing.md) | +| Jupiter swap β†’ USDC auto-topup | [x402-defi-jupiter.md](references/x402-defi-jupiter.md) | +| Orca/Raydium/Drift analytics APIs | [x402-defi-protocols.md](references/x402-defi-protocols.md) | +| Helius RPC/DAS, Pyth oracles, Cloudflare | [x402-data-infrastructure.md](references/x402-data-infrastructure.md) | +| Multi-agent commerce, orchestrator/worker | [x402-multi-agent.md](references/x402-multi-agent.md) | +| Ecosystem resources, DeFi, infrastructure, and roadmap docs | [docs/index.md](../docs/index.md) | +| Build-time and runtime agent workflows & flowcharts | [docs/agent_workflow.md](../docs/agent_workflow.md) | + +--- + +## Specialized Agents + +This skill provides three specialized agents to assist you: + +1. **`x402-architect`**: Use for high-level system design, key vaulting, and choosing the right facilitator setup. +2. **`x402-builder`**: Use for generating concrete, type-safe TypeScript code for clients and servers. +3. **`x402-auditor`**: Use to aggressively review code against the `x402-security-rules.md`. Trigger via `/audit-routes`. + +--- + +## Defaults (Opinionated) + +| Concern | Default | +|---|---| +| **Protocol version** | x402 v2 (x402-foundation spec) | +| **Network** | Solana Mainnet (`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp`) | +| **Test network** | Solana Devnet (`solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1`) | +| **Payment scheme** | `exact` via `ExactSvmScheme` from `@x402/svm` | +| **Payment token** | USDC SPL β€” Mainnet: `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` | +| **Server framework** | Hono (edge-first) or Express for Node.js | +| **Client wrapper** | `@x402/fetch` with `wrapFetchWithPayment` or `wrapFetchWithPaymentFromConfig` | +| **Swap router** | Jupiter v6 for any token β†’ USDC conversion | +| **RPC provider** | Helius (mainnet), public devnet for testing | +| **Key management** | env vars only; never hardcode; KMS for production | +| **Spend controls** | Always add: max-per-request, daily-budget, domain-allowlist, receipt-log | +| **Server safety** | Always bind: method, URL, price, network, asset, payee, quote-expiry | +| **Testing** | Vitest + devnet USDC airdrop + mock facilitator | + +--- + +## Key Package Versions (2026) + +```bash +# Core x402 +npm install @x402/core @x402/svm @x402/fetch + +# Server middleware (pick one) +npm install @x402/express # Express.js +npm install @x402/hono # Hono (recommended) +npm install @x402/next # Next.js App Router +npm install @x402/fastify # Fastify + +# Solana signer utilities used by @x402/svm v2 +npm install @solana/kit @scure/base dotenv + +# DeFi (install only what you need) +npm install @jup-ag/api # Jupiter v6 REST client +npm install @orca-so/whirlpools-sdk @orca-so/common-sdk # Orca +npm install @raydium-io/raydium-sdk-v2 # Raydium +npm install @meteora-ag/dlmm # Meteora DLMM +npm install @drift-labs/sdk # Drift Protocol +npm install @pythnetwork/client # Pyth oracles + +# Agent frameworks +npm install @sendaifun/solana-agent-kit # Solana Agent Kit +npm install langchain @langchain/community # LangChain +``` + +--- + +## Quick Architecture Patterns + +### Pattern A β€” Paid REST API (Seller) +``` +Your Service β†’ Express/Hono + @x402/express middleware +Client Agent β†’ @x402/fetch wrapper auto-pays 402 +Settlement β†’ USDC transferred on Solana, receipt returned +``` + +### Pattern B β€” DeFi-Aware Agent (Buyer) +``` +Agent Wallet β†’ holds SOL + USDC +On 402 β†’ check USDC balance β†’ if low, swap SOLβ†’USDC via Jupiter + β†’ pay with @x402/fetch β†’ log receipt β†’ continue task +``` + +### Pattern C β€” MCP Tool Marketplace +``` +MCP Server β†’ wrapped by HTTP Gateway (Express/Hono) +Tool pricing β†’ defined in MCP_PRICING_MAP +Agent calls β†’ POST /mcp/call-tool β†’ 402 β†’ auto-pay β†’ result +``` + +### Pattern D β€” Agent-to-Agent Commerce +``` +Orchestrator Agent β†’ discovers peer agents via service registry + β†’ calls peer service β†’ receives 402 + β†’ pays with its own USDC wallet + β†’ forwards result to user +``` + +--- + +## Operating Procedure + +1. **Classify the task** using the routing table above. +2. **Adopt the appropriate persona** (`architect`, `builder`, or `auditor`) when the environment does not support external agent files. +3. **Read the specific reference file** β€” do not load all references at once. +4. **Check the Defaults** β€” use opinionated defaults unless overridden by user. +5. **Apply security rules** (`rules/x402-security-rules.md`) β€” always include spend caps and key management. +6. **Write tests** β€” always include devnet test patterns. diff --git a/skill/references/x402-agent-kit.md b/skill/references/x402-agent-kit.md new file mode 100644 index 0000000..f5735c0 --- /dev/null +++ b/skill/references/x402-agent-kit.md @@ -0,0 +1,233 @@ +# Agent Frameworks (LangChain, LangGraph, and Vercel AI SDK) + +Use this reference to integrate paid x402 actions as tools inside modern agent frameworks, including LangChain, LangGraph, and the Vercel AI SDK. + +--- + +## 1. Vercel AI SDK `tool()` Integration + +The Vercel AI SDK uses the `tool` function to define agent actions. The implementation below registers a gated x402 tool with a local spending guardrail. + +```typescript +import { tool } from "ai"; +import { z } from "zod"; +import { wrapFetchWithPayment } from "@x402/fetch"; +import { createSvmClient } from "@x402/svm/client"; +import { toClientSvmSigner } from "@x402/svm"; +import { createKeyPairSignerFromBytes } from "@solana/kit"; +import { base58 } from "@scure/base"; + +// 1. Initialize the paid fetch client +const keypair = await createKeyPairSignerFromBytes( + base58.decode(process.env.SVM_PRIVATE_KEY!) +); + +const svmClient = createSvmClient({ + signer: toClientSvmSigner(keypair), + rpcUrl: process.env.SOLANA_RPC_URL!, +}); + +const paidFetch = wrapFetchWithPayment(fetch, svmClient); + +// 2. Define the spend cap and policy +const MAX_USDC_BUDGET_ATOMIC = 100_000n; // 0.10 USDC per call +let sessionSpendAtomic = 0n; +const MAX_SESSION_SPEND_ATOMIC = 1_000_000n; // 1.00 USDC total budget + +/** + * Paid tool for Vercel AI SDK + */ +export const paidMarketDataTool = tool({ + description: "Queries high-value market intelligence data. Costs up to 0.10 USDC.", + parameters: z.object({ + tokenSymbol: z.string().describe("The token symbol to fetch analytics for (e.g. SOL, JUP)"), + }), + execute: async ({ tokenSymbol }) => { + // Enforce pre-execution spend limits + if (sessionSpendAtomic + MAX_USDC_BUDGET_ATOMIC > MAX_SESSION_SPEND_ATOMIC) { + throw new Error("AGENT_BUDGET_EXHAUSTED: Tool call blocked to prevent exceeding session budget."); + } + + const targetUrl = `https://api.alpha-signals.com/v1/market-data?symbol=${tokenSymbol}`; + + try { + const response = await paidFetch(targetUrl, { + headers: { + "Idempotency-Key": crypto.randomUUID(), + }, + }); + + if (!response.ok) { + throw new Error(`Market data provider returned HTTP ${response.status}`); + } + + // Track paid amount from payment receipt headers + const receiptRaw = response.headers.get("PAYMENT-RESPONSE"); + if (receiptRaw) { + const receipt = JSON.parse(receiptRaw); + const amountSpent = BigInt(receipt.amountAtomic || 0); + sessionSpendAtomic += amountSpent; + console.log(`[Spend Update] Spent ${amountSpent} atomic USDC. Session total: ${sessionSpendAtomic}`); + } + + const data = await response.json(); + return { success: true, data }; + } catch (error: any) { + return { success: false, error: error.message }; + } + }, +}); +``` + +--- + +## 2. LangGraph Stateful Agent Integration + +In stateful agent frameworks like LangGraph, the agent's total spend and billing receipts should be stored in the graph's global state. This prevents state loss across multi-turn LLM reasoning loops. + +```typescript +import { StateGraph, Annotation } from "@langchain/langgraph"; +import { wrapFetchWithPayment } from "@x402/fetch"; + +// 1. Define Graph State including the payment ledger +const AgentState = Annotation.Root({ + messages: Annotation({ + reducer: (x, y) => x.concat(y), + default: () => [], + }), + totalSpentAtomicUsdc: Annotation({ + reducer: (x, y) => x + y, + default: () => 0n, + }), + paymentReceipts: Annotation({ + reducer: (x, y) => x.concat(y), + default: () => [], + }), +}); + +// 2. Define the paid node +async function callPaidTranslationNode(state: typeof AgentState.State) { + const lastMessage = state.messages[state.messages.length - 1]; + const textToTranslate = lastMessage.content; + + // Enforce graph-level budget protection + const BUDGET_LIMIT = 500_000n; // 0.50 USDC + if (state.totalSpentAtomicUsdc >= BUDGET_LIMIT) { + return { + messages: [{ role: "assistant", content: "I have reached my maximum translation budget limit." }] + }; + } + + // Execute x402 call + const targetUrl = "https://paid.translator.agent/translate"; + const client = getGlobalSvmPaymentClient(); // Returns wrapped svm client + const paidFetch = wrapFetchWithPayment(fetch, client); + + const response = await paidFetch(targetUrl, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ text: textToTranslate, targetLang: "es" }) + }); + + const receipt = response.headers.get("PAYMENT-RESPONSE") || ""; + const result = await response.json(); + + // Extract payment details to return state updates + let txSpent = 0n; + if (receipt) { + const parsedReceipt = JSON.parse(receipt); + txSpent = BigInt(parsedReceipt.amountAtomic || 0); + } + + return { + messages: [{ role: "assistant", content: `Translation: ${result.translatedText}` }], + totalSpentAtomicUsdc: txSpent, + paymentReceipts: [receipt] + }; +} +``` + +--- + +## 3. Solana Agent Kit v2 Integration + +When integrating with the `solana-agent-kit`, inspect the version pattern to safely extract keypairs/signers. Avoid assuming `.keypair` exists directly on the agent class. + +```typescript +import { SolanaAgentKit } from "solana-agent-kit"; +import { createKeyPairSignerFromBytes } from "@solana/kit"; +import { toClientSvmSigner } from "@x402/svm"; + +/** + * Safely extracts signer from SolanaAgentKit instance + */ +export async function getSignerFromAgentKit( + agent: SolanaAgentKit +): Promise> { + // 1. Detect and extract secret key bytes safely + let secretKeyBytes: Uint8Array; + + if (typeof agent.wallet?.secretKey === "object") { + secretKeyBytes = new Uint8Array(Object.values(agent.wallet.secretKey)); + } else if (agent.wallet instanceof Uint8Array) { + secretKeyBytes = agent.wallet; + } else if (typeof agent.wallet === "string") { + // If wallet is stored as base58 string + const { base58 } = await import("@scure/base"); + secretKeyBytes = base58.decode(agent.wallet); + } else { + throw new Error("Unable to resolve private key bytes from SolanaAgentKit wallet instance"); + } + + // 2. Create the @solana/kit signer + const keypairSigner = await createKeyPairSignerFromBytes(secretKeyBytes); + return toClientSvmSigner(keypairSigner); +} +``` + +--- + +## 4. Budget Exhaustion & User Handover + +If an agent exhausts its allocated budget, it must gracefully pause, format a summary of its spending, and hand control back to the user. + +```typescript +export class BudgetExhaustedError extends Error { + public totalSpent: bigint; + public budgetLimit: bigint; + + constructor(message: string, totalSpent: bigint, budgetLimit: bigint) { + super(message); + this.name = "BudgetExhaustedError"; + this.totalSpent = totalSpent; + this.budgetLimit = budgetLimit; + } +} + +/** + * Executes a paid action and handles budget exhaustion + */ +export async function executeGatedActionWithFallback( + actionFn: () => Promise, + currentSpend: bigint, + budgetLimit: bigint +): Promise { + if (currentSpend >= budgetLimit) { + throw new BudgetExhaustedError( + "Agent budget exhausted. Awaiting manual user top-up or budget increase.", + currentSpend, + budgetLimit + ); + } + + try { + return await actionFn(); + } catch (error: any) { + if (error.message?.includes("BUDGET_EXHAUSTED")) { + // Format manual intervention report for user UI + console.warn(`[BUDGET PAUSE] Agent paused. Spent: ${currentSpend} / Limit: ${budgetLimit}`); + } + throw error; + } +} +``` diff --git a/skill/references/x402-client-patterns.md b/skill/references/x402-client-patterns.md new file mode 100644 index 0000000..283c3de --- /dev/null +++ b/skill/references/x402-client-patterns.md @@ -0,0 +1,106 @@ +# x402 Client Integration Patterns + +Use this reference when building buyer agents that call paid HTTP APIs and automatically satisfy x402 `402 Payment Required` challenges. + +## 1. Preferred fetch wrapper + +Use `@x402/fetch` instead of parsing payment headers yourself. For Solana/SVM v2, create an `@solana/kit` signer, convert it with `toClientSvmSigner`, then register it with the x402 fetch wrapper. + +```typescript +import { wrapFetchWithPayment } from "@x402/fetch"; +import { createSvmClient } from "@x402/svm/client"; +import { toClientSvmSigner } from "@x402/svm"; +import { createKeyPairSignerFromBytes } from "@solana/kit"; +import { base58 } from "@scure/base"; + +const keypair = await createKeyPairSignerFromBytes( + base58.decode(process.env.SVM_PRIVATE_KEY!) +); + +const signer = toClientSvmSigner(keypair); +const client = createSvmClient({ + signer, + rpcUrl: process.env.SOLANA_RPC_URL, +}); + +const paidFetch = wrapFetchWithPayment(fetch, client); + +const response = await paidFetch("https://api.provider.com/gated-endpoint", { + headers: { + "Idempotency-Key": crypto.randomUUID(), + }, +}); + +if (!response.ok) { + throw new Error(`Paid request failed: ${response.status}`); +} + +const paymentReceipt = response.headers.get("PAYMENT-RESPONSE"); +const data = await response.json(); +``` + +## 2. Config-driven fetch wrapper + +If using `wrapFetchWithPaymentFromConfig`, keep the network as a v2 CAIP-2 ID: + +```typescript +import { wrapFetchWithPaymentFromConfig } from "@x402/fetch"; +import { ExactSvmScheme, toClientSvmSigner } from "@x402/svm"; +import { createKeyPairSignerFromBytes } from "@solana/kit"; +import { base58 } from "@scure/base"; + +const keypair = await createKeyPairSignerFromBytes( + base58.decode(process.env.SVM_PRIVATE_KEY!) +); + +const paidFetch = wrapFetchWithPaymentFromConfig(fetch, { + schemes: [ + { + network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + client: new ExactSvmScheme(toClientSvmSigner(keypair), { + rpcUrl: process.env.SOLANA_RPC_URL, + }), + }, + ], +}); +``` + +## 3. Spend policy guardrail + +Do not rely on the remote server's price claim. Add local policy before using a paid fetch wrapper: + +```typescript +const allowedDomains = new Set(["api.provider.com"]); +const maxAtomicUsdcPerRequest = 250_000n; // 0.25 USDC, 6 decimals +let spentTodayAtomicUsdc = 0n; +const dailyLimitAtomicUsdc = 5_000_000n; // 5 USDC + +function assertSpendAllowed(url: string, requestedAtomicUsdc: bigint) { + const host = new URL(url).host; + if (!allowedDomains.has(host)) { + throw new Error(`Blocked paid request to untrusted domain: ${host}`); + } + if (requestedAtomicUsdc > maxAtomicUsdcPerRequest) { + throw new Error("Blocked paid request over per-request cap"); + } + if (spentTodayAtomicUsdc + requestedAtomicUsdc > dailyLimitAtomicUsdc) { + throw new Error("Blocked paid request over daily cap"); + } +} +``` + +When the SDK exposes payment-selection hooks, enforce: + +- trusted domain +- expected CAIP-2 network +- expected USDC mint +- expected payee or payee allowlist +- max amount in atomic USDC units +- quote expiry +- daily/session budget + +## 4. Avoid manual header flows + +Avoid Axios interceptors or custom logic that parses `PAYMENT-REQUIRED` / `X-PAYMENT` by hand. Only use a manual flow when the SDK wrapper cannot be used, and then treat it as security-critical protocol code. + +Always log `PAYMENT-RESPONSE` after successful paid calls for reconciliation. diff --git a/skill/references/x402-data-infrastructure.md b/skill/references/x402-data-infrastructure.md new file mode 100644 index 0000000..13afc99 --- /dev/null +++ b/skill/references/x402-data-infrastructure.md @@ -0,0 +1,303 @@ +# Gating Data Infrastructure with x402 + +Use this reference to implement paid APIs proxying high-value data infrastructure on Solana, including Helius RPCs (DAS API, priority fees), Pyth Network oracles, and deployments via Cloudflare Workers. + +--- + +## 1. Helius RPC Paid Proxy Pattern + +This pattern gates access to expensive RPC operations (like DAS indexer queries or live priority fee estimates) with x402 payment requirements. + +```typescript +import { Hono } from "hono"; +import { paymentMiddleware } from "@x402/hono"; +import { ExactSvmScheme } from "@x402/svm"; + +const app = new Hono(); +const HELIUS_RPC_URL = `https://mainnet.helius-rpc.com/?api-key=${process.env.HELIUS_API_KEY}`; + +// Define paid gating middleware +app.use( + "/api/v1/infra/*", + paymentMiddleware({ + "POST /api/v1/infra/das/assets": { + accepts: [ + { + scheme: ExactSvmScheme.scheme, + network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", + maxAmountRequired: "20000", // 0.02 USDC + payTo: process.env.PAYEE_WALLET!, + asset: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + maxAgeSeconds: 60, + }, + ], + description: "DAS indexer asset lookup (getAssetsByOwner).", + }, + "POST /api/v1/infra/priority-fee": { + accepts: [ + { + scheme: ExactSvmScheme.scheme, + network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", + maxAmountRequired: "5000", // 0.005 USDC + payTo: process.env.PAYEE_WALLET!, + asset: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + maxAgeSeconds: 60, + }, + ], + description: "Get real-time optimal priority fee recommendations.", + }, + }) +); + +/** + * Endpoint: DAS Asset Search + */ +app.post("/api/v1/infra/das/assets", async (c) => { + const { ownerAddress, page = 1, limit = 10 } = await c.req.json(); + + if (!ownerAddress) { + return c.json({ error: "Missing 'ownerAddress'" }, 400); + } + + try { + const response = await fetch(HELIUS_RPC_URL, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: "das-assets", + method: "getAssetsByOwner", + params: { + ownerAddress, + page, + limit, + displayOptions: { showFungible: true }, + }, + }), + }); + + const data = await response.json(); + return c.json(data); + } catch (error: any) { + return c.json({ error: `DAS proxy request failed: ${error.message}` }, 500); + } +}); + +/** + * Endpoint: Priority Fee Estimator + */ +app.post("/api/v1/infra/priority-fee", async (c) => { + const { accountKeys } = await c.req.json(); + + if (!accountKeys || !Array.isArray(accountKeys)) { + return c.json({ error: "Missing or invalid 'accountKeys'" }, 400); + } + + try { + const response = await fetch(HELIUS_RPC_URL, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: "priority-fee", + method: "getPriorityFeeEstimate", + params: { + accountKeys, + options: { recommended: true }, + }, + }), + }); + + const data = await response.json(); + return c.json(data); + } catch (error: any) { + return c.json({ error: `Priority fee proxy failed: ${error.message}` }, 500); + } +}); +``` + +--- + +## 2. Gating Pyth Network Oracles + +Monetizes price feeds fetched via Pyth's Hermes API. Consumers pay a micro-fee for the latest verified price update payload. + +```typescript +const PYTH_HERMES_API = "https://hermes.pyth.network/v2/updates/price/latest"; + +app.use( + "/api/v1/infra/pyth/price", + paymentMiddleware({ + "GET /api/v1/infra/pyth/price": { + accepts: [ + { + scheme: ExactSvmScheme.scheme, + network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", + maxAmountRequired: "2000", // 0.002 USDC + payTo: process.env.PAYEE_WALLET!, + asset: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + maxAgeSeconds: 30, + }, + ], + description: "Fetch premium Pyth price feed payload with cryptographic signature.", + }, + }) +); + +app.get("/api/v1/infra/pyth/price", async (c) => { + const feedId = c.req.query("feedId"); + if (!feedId) { + return c.json({ error: "Missing 'feedId' query parameter" }, 400); + } + + try { + const url = `${PYTH_HERMES_API}?ids[]=${feedId}`; + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Hermes API error: ${response.status}`); + } + + const priceData = await response.json(); + return c.json(priceData); + } catch (error: any) { + return c.json({ error: `Failed to fetch Pyth oracle payload: ${error.message}` }, 500); + } +}); +``` + +--- + +## 3. Cloudflare Worker Deployment Pattern + +A serverless implementation of an x402 gateway using a Cloudflare Worker. + +### `wrangler.toml` Configuration +```toml +name = "x402-gateway-worker" +main = "src/index.ts" +compatibility_date = "2026-06-19" + +[vars] +EXPECTED_NETWORK = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" +PAYEE_WALLET = "Merch1111111111111111111111111111111111111" +USDC_MINT = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" # Devnet + +# Bind secret keys securely in the dashboard using wrangler secret put HELIUS_API_KEY +``` + +### `src/index.ts` Cloudflare Worker Implementation +```typescript +export interface Env { + HELIUS_API_KEY: string; + EXPECTED_NETWORK: string; + PAYEE_WALLET: string; + USDC_MINT: string; +} + +export default { + async fetch(request: Request, env: Env): Promise { + const url = new URL(request.url); + + // Bypass payment check for health status + if (url.pathname === "/health") { + return new Response("OK", { status: 200 }); + } + + // 1. Inspect payment header + const paymentTxid = request.headers.get("x-payment-txid"); + const requiredAmountUsdc = 0.05; // $0.05 USDC + + if (!paymentTxid) { + // Return HTTP 402 challenge if header is missing + return new Response( + JSON.stringify({ + error: "Payment Required", + payTo: env.PAYEE_WALLET, + amount: requiredAmountUsdc, + network: env.EXPECTED_NETWORK, + asset: env.USDC_MINT, + }), + { + status: 402, + headers: { + "Content-Type": "application/json", + "WWW-Authenticate": `x402 scheme="exact", recipient="${env.PAYEE_WALLET}", amount="${requiredAmountUsdc}", asset="${env.USDC_MINT}"`, + }, + } + ); + } + + // 2. Validate the payment txid via Helius transaction parsing endpoint + try { + const isPaid = await verifyHeliusPayment(paymentTxid, requiredAmountUsdc, env); + if (!isPaid) { + return new Response(JSON.stringify({ error: "Invalid payment transaction" }), { + status: 403, + headers: { "Content-Type": "application/json" }, + }); + } + } catch (err: any) { + return new Response(JSON.stringify({ error: `Verification failed: ${err.message}` }), { + status: 500, + headers: { "Content-Type": "application/json" }, + }); + } + + // 3. Payment Verified: Forward the request or return high-value data + return new Response( + JSON.stringify({ + success: true, + data: "Premium data-infrastructure payload delivered successfully.", + }), + { + status: 200, + headers: { + "Content-Type": "application/json", + "PAYMENT-RESPONSE": JSON.stringify({ txid: paymentTxid, status: "settled" }), + }, + } + ); + }, +}; + +/** + * Verification helper using Helius Transaction API + */ +async function verifyHeliusPayment(txid: string, expectedAmount: number, env: Env): Promise { + const heliusUrl = `https://api.helius.xyz/v0/transactions/?api-key=${env.HELIUS_API_KEY}`; + + const response = await fetch(heliusUrl, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ transactions: [txid] }), + }); + + if (!response.ok) return false; + + const txData = (await response.json()) as any[]; + const tx = txData[0]; + + if (!tx || !tx.tokenTransfers) return false; + + // Validate the payment transfer details + return tx.tokenTransfers.some((transfer: any) => { + return ( + transfer.toUserAccount === env.PAYEE_WALLET && + transfer.tokenMint === env.USDC_MINT && + parseFloat(transfer.tokenAmount) >= expectedAmount + ); + }); +} +``` + +--- + +## 4. Webhook Async Payment Verification Flow + +For high-throughput systems, verifying payments synchronously via raw RPC/DAS requests can result in performance bottlenecks. Instead, use an asynchronous webhook model: + +1. **Client requests service** with a transaction ID. +2. **Server enqueues job** and immediately returns `202 Accepted`. +3. **Webhook endpoint** receives confirmation from Helius/Validator when transaction finality is reached. +4. **Server updates local database** state (e.g. Postgres / Redis cache). +5. **Client pulls results** or receives push via WebSockets once payment is marked `settled`. diff --git a/skill/references/x402-defi-jupiter.md b/skill/references/x402-defi-jupiter.md new file mode 100644 index 0000000..d5fa249 --- /dev/null +++ b/skill/references/x402-defi-jupiter.md @@ -0,0 +1,260 @@ +# Jupiter SOL-to-USDC Swap & Auto-Topup Pattern + +Use this reference to implement automated SOL-to-USDC swaps for buyer agents. This pattern, referred to as **Pattern B (Auto-Topup on 402)**, ensures that if an agent's USDC balance is insufficient to satisfy an x402 payment challenge, the agent automatically executes a Jupiter swap to convert SOL to USDC before retrying the paid request. + +--- + +## 1. Network & Mint Constants + +For all Jupiter interactions, ensure you use the correct USDC mint and CAIP-2 network IDs. Do not hardcode private keys. + +| Network | CAIP-2 ID | USDC Mint Address | Decimals | +| :--- | :--- | :--- | :--- | +| **Mainnet-Beta** | `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` | 6 | +| **Devnet** | `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` | `4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU` | 6 | + +--- + +## 2. Implementing the Jupiter Swap Utility + +This implementation uses the modern `@solana/kit` and standard `fetch` API to interact with Jupiter v6. + +```typescript +import { + createSolanaRpc, + createKeyPairSignerFromBytes, + getBase64Decoder, + getBase64Encoder, + signTransaction +} from "@solana/kit"; +import { base58 } from "@scure/base"; + +const JUPITER_QUOTE_API = "https://quote-api.jup.ag/v6"; +const SOL_MINT = "So11111111111111111111111111111111111111112"; +const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; // Mainnet default + +interface JupiterQuoteResponse { + inputMint: string; + inAmount: string; + outputMint: string; + outAmount: string; + otherAmountThreshold: string; + swapMode: string; + slippageBps: number; + platformFee?: null | { feeBps: number }; + priceImpactPct: string; + routePlan: Array; + contextSlot: number; + timeTaken: number; +} + +interface SwapRequest { + quoteResponse: JupiterQuoteResponse; + userPublicKey: string; + wrapAndUnwrapSol: boolean; + prioritizationFeeLamports?: number; +} + +interface SwapResponse { + swapTransaction: string; // Base64 serialized transaction + lastValidBlockHeight: number; + prioritizationFeeLamports: number; +} + +/** + * Fetches a quote from Jupiter for SOL -> USDC swap + */ +export async function getJupiterQuote( + amountLamports: bigint, + slippageBps = 50 // 0.5% +): Promise { + const url = `${JUPITER_QUOTE_API}/quote?inputMint=${SOL_MINT}&outputMint=${USDC_MINT}&amount=${amountLamports.toString()}&slippageBps=${slippageBps}`; + + const response = await fetch(url); + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`Jupiter quote failed: ${response.status} - ${errorText}`); + } + + const data = (await response.json()) as JupiterQuoteResponse; + return data; +} + +/** + * Executes a Jupiter swap using @solana/kit transaction signing and broadcasting + */ +export async function executeJupiterSwap( + quote: JupiterQuoteResponse, + signer: ReturnType, + rpcUrl: string +): Promise { + const rpc = createSolanaRpc(rpcUrl); + + // 1. Request swap transaction from Jupiter + const swapRequest: SwapRequest = { + quoteResponse: quote, + userPublicKey: signer.address, + wrapAndUnwrapSol: true, + }; + + const response = await fetch(`${JUPITER_QUOTE_API}/swap`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(swapRequest), + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`Jupiter swap request failed: ${response.status} - ${errorText}`); + } + + const { swapTransaction } = (await response.json()) as SwapResponse; + + // 2. Deserialize base64 transaction bytes + const transactionBytes = getBase64Decoder().decode(swapTransaction); + + // In @solana/kit, raw transaction bytes can be signed and sent. + // Note: For versioned transactions, sign using signTransaction. + // First, reconstruct the transaction model or sign the raw bytes. + // If the SDK returns a fully formed transaction, sign it using the signer: + const txToSign = { + messageBytes: transactionBytes, + signatures: {} + }; + + const signedTx = await signTransaction([signer], txToSign as any); + const serializedSignedTx = getBase64Encoder().encode(signedTx.messageBytes); + + // 3. Send and confirm transaction + const txid = await rpc.sendTransaction(serializedSignedTx, { + encoding: "base64", + skipPreflight: true, + }).send(); + + return txid; +} +``` + +--- + +## 3. Pattern B: Auto-Topup Implementation + +A buyer agent should monitor its local USDC balance before initiating paid requests. If the required amount exceeds the balance, it initiates a top-up swap using the utility function. + +### Safeguard: Price Impact Guardrail +Always inspect the `priceImpactPct` parameter in the quote response. To protect the agent from sandwich attacks and severe slippage, **reject quotes where the price impact exceeds 1.0% (0.01)**. + +```typescript +import { getJupiterQuote, executeJupiterSwap } from "./jupiter-swap"; +import { createKeyPairSignerFromBytes, createSolanaRpc } from "@solana/kit"; + +const MAX_PRICE_IMPACT_PCT = 1.0; // 1% + +/** + * Top up the agent's USDC wallet by swapping SOL -> USDC + */ +export async function topUpUsdcWallet( + targetUsdcAtomic: bigint, + signer: ReturnType, + rpcUrl: string +): Promise { + // Estimate SOL amount required for target USDC. Use 1000 lamports per 0.0006 USDC as a safe buffer. + // Fetch a reverse quote or a quote with a buffer: + // For simplicity, we query a quote for 0.05 SOL and scale it, or perform a direct SOL quote. + const estimatedSolLamports = 50_000_000n; // 0.05 SOL estimate + const quote = await getJupiterQuote(estimatedSolLamports); + + const priceImpact = parseFloat(quote.priceImpactPct); + if (priceImpact > MAX_PRICE_IMPACT_PCT) { + throw new Error(`Jupiter swap rejected: high price impact of ${priceImpact}%`); + } + + // Calculate actual SOL required to meet target USDC based on quote rate + const outAmountUsdc = BigInt(quote.outAmount); + if (outAmountUsdc === 0n) throw new Error("Zero output amount from Jupiter quote"); + + const exactSolNeeded = (targetUsdcAtomic * estimatedSolLamports) / outAmountUsdc; + const solWithBuffer = (exactSolNeeded * 105n) / 100n; // Add 5% buffer for slippage + + console.log(`[Top-up] Swapping ${solWithBuffer} lamports for target ${targetUsdcAtomic} atomic USDC`); + + const finalQuote = await getJupiterQuote(solWithBuffer); + const txid = await executeJupiterSwap(finalQuote, signer, rpcUrl); + console.log(`[Top-up] Auto-swap transaction executed successfully. Tx ID: ${txid}`); +} +``` + +--- + +## 4. Hooking Into Client Spend Verification + +Integrate the auto-topup step directly into your agent's payment client logic: + +```typescript +import { getAssociatedTokenAddress } from "@solana/spl-token"; +import { createSolanaRpc, Address } from "@solana/kit"; + +export async function assertAndTopUpSpend( + url: string, + requestedAtomicUsdc: bigint, + signer: any, + rpcUrl: string +) { + const rpc = createSolanaRpc(rpcUrl); + + // 1. Get associated token account for USDC + const usdcMint = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" as Address; + const usdcAta = await getAssociatedTokenAddress( + new PublicKey(usdcMint), // Using spl-token helper + new PublicKey(signer.address) + ); + + // 2. Fetch current balance + let currentBalance = 0n; + try { + const balanceResponse = await rpc.getTokenAccountBalance(usdcAta.toBase58() as Address).send(); + currentBalance = BigInt(balanceResponse.value.amount); + } catch (error) { + console.warn("USDC ATA does not exist or has zero balance. Creating account may be required."); + } + + // 3. Check if balance is sufficient + if (currentBalance < requestedAtomicUsdc) { + const deficit = requestedAtomicUsdc - currentBalance; + console.log(`[Auto-Topup] Deficit of ${deficit} USDC detected. Initiating Jupiter auto-swap...`); + await topUpUsdcWallet(deficit, signer, rpcUrl); + } +} +``` + +--- + +## 5. Devnet Mock Setup for Tests + +Since Jupiter v6 mainnet route API requires mainnet liquidity, testing on Devnet requires either a custom mock route API or bypassing the swap request by calling a mock token exchange program on Devnet. + +### Devnet USDC Mint +Devnet USDC Mint: `4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU` + +### Mocking Jupiter in Vitest +```typescript +import { vi, describe, it, expect } from "vitest"; + +describe("Pattern B Auto-Topup Mock Test", () => { + it("should intercept low balance and execute mock swap", async () => { + const mockTopUp = vi.fn().mockImplementation(async (amount: bigint) => { + console.log(`[Mock Swap] Swapped SOL for ${amount} Devnet USDC`); + return "mock-tx-id"; + }); + + const balance = 10_000n; // 0.01 USDC + const required = 50_000n; // 0.05 USDC + + if (balance < required) { + await mockTopUp(required - balance); + } + + expect(mockTopUp).toHaveBeenCalledWith(40_000n); + }); +}); +``` diff --git a/skill/references/x402-defi-protocols.md b/skill/references/x402-defi-protocols.md new file mode 100644 index 0000000..ba1379f --- /dev/null +++ b/skill/references/x402-defi-protocols.md @@ -0,0 +1,289 @@ +# Gating DeFi Protocol Data with x402 + +Use this reference to build paid API endpoints that sell DeFi protocol data (Orca Whirlpools positions, Raydium farm APYs, Meteora DLMM analytics, and Drift perp PnL) to consumer agents. + +--- + +## 1. Design & Pricing Models + +DeFi protocol data is highly time-sensitive. Agents querying this data for arbitrage or yield optimization require high availability and low latency. You can monetize these endpoints by setting up two pricing tiers: + +1. **Real-time Tier (Premium)**: Hits the Solana RPC directly to fetch live state. Gated with a higher x402 payment fee. +2. **Cached Tier (Standard)**: Serves data cached in memory or Redis (updated every 30-60 seconds). Gated with a lower x402 payment fee. + +--- + +## 2. Server setup with Hono Middleware + +The following Hono server sets up paid endpoints for Orca, Raydium, Meteora, and Drift analytics. + +```typescript +import { Hono } from "hono"; +import { paymentMiddleware } from "@x402/hono"; +import { ExactSvmScheme } from "@x402/svm"; +import { createSolanaRpc, Address } from "@solana/kit"; + +// Setup Hono app +const app = new Hono(); + +// Connect to Solana RPC +const SOLANA_RPC_URL = process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com"; +const rpc = createSolanaRpc(SOLANA_RPC_URL); + +// Devnet / Mainnet USDC configurations +const DEVNET_USDC = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"; +const MAINNET_USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; + +// Register x402 routes +app.use( + "/api/v1/defi/*", + paymentMiddleware({ + // Orca Whirlpools position analytics + "GET /api/v1/defi/orca/position": { + accepts: [ + { + scheme: ExactSvmScheme.scheme, + network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", // Mainnet + maxAmountRequired: "10000", // 0.01 USDC (6 decimals) + payTo: process.env.PAYEE_WALLET!, + asset: MAINNET_USDC, + maxAgeSeconds: 60, + }, + ], + description: "Retrieve real-time liquidity position analytics for Orca Whirlpool.", + }, + // Raydium APY data + "GET /api/v1/defi/raydium/yields": { + accepts: [ + { + scheme: ExactSvmScheme.scheme, + network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", + maxAmountRequired: "5000", // 0.005 USDC + payTo: process.env.PAYEE_WALLET!, + asset: MAINNET_USDC, + maxAgeSeconds: 60, + }, + ], + description: "Cached yield and farm APY data for Raydium pools.", + }, + // Meteora Bin analysis + "GET /api/v1/defi/meteora/bins": { + accepts: [ + { + scheme: ExactSvmScheme.scheme, + network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", + maxAmountRequired: "15000", // 0.015 USDC + payTo: process.env.PAYEE_WALLET!, + asset: MAINNET_USDC, + maxAgeSeconds: 60, + }, + ], + description: "Retrieve Meteora DLMM active bins and price distributions.", + }, + // Drift Perp analytics + "GET /api/v1/defi/drift/perp-pnl": { + accepts: [ + { + scheme: ExactSvmScheme.scheme, + network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", + maxAmountRequired: "20000", // 0.02 USDC + payTo: process.env.PAYEE_WALLET!, + asset: MAINNET_USDC, + maxAgeSeconds: 60, + }, + ], + description: "Drift perpetual position and unrealized PnL data.", + }, + }) +); +``` + +--- + +## 3. Orca Whirlpools Gated Endpoint + +Fetches real-time position metadata using `@orca-so/whirlpools-sdk` pattern, returning active liquidity. + +```typescript +import { WhirlpoolContext, ORCA_WHIRLPOOL_PROGRAM_ID } from "@orca-so/whirlpools-sdk"; +import { PublicKey } from "@solana/web3.js"; // Standard for current Orca SDK integrations + +app.get("/api/v1/defi/orca/position", async (c) => { + const positionAddress = c.req.query("address"); + if (!positionAddress) { + return c.json({ error: "Missing 'address' query parameter" }, 400); + } + + try { + // For legacy SDK compatibility, wrap RPC connection + const connection = new (await import("@solana/web3.js")).Connection(SOLANA_RPC_URL); + const mockWallet = { + publicKey: PublicKey.default, + signTransaction: async (tx: any) => tx, + signAllTransactions: async (txs: any) => txs, + }; + + const context = WhirlpoolContext.from( + connection, + mockWallet, + ORCA_WHIRLPOOL_PROGRAM_ID + ); + + // Fetch position account data + const positionPubKey = new PublicKey(positionAddress); + const position = await context.client.getPosition(positionPubKey); + const positionData = position.getData(); + + return c.json({ + positionAddress, + whirlpool: positionData.whirlpool.toBase58(), + liquidity: positionData.liquidity.toString(), + tickLowerIndex: positionData.tickLowerIndex, + tickUpperIndex: positionData.tickUpperIndex, + }); + } catch (error: any) { + return c.json({ error: `Failed to fetch Orca position: ${error.message}` }, 500); + } +}); +``` + +--- + +## 4. Raydium Yields Gated Endpoint + +Returns yield farm calculations. To keep API response times low, use a cached data source updated out-of-band. + +```typescript +// Local in-memory cache representation +let raydiumCache = { + lastUpdated: 0, + data: [] as any[] +}; + +// Out-of-band fetcher (e.g. cron job or background runner) +async function updateRaydiumCache() { + try { + const response = await fetch("https://api.raydium.io/v2/main/pairs"); + if (response.ok) { + const data = await response.json(); + raydiumCache = { + lastUpdated: Date.now(), + data: data.slice(0, 50) // Cache top 50 pools + }; + } + } catch (err) { + console.error("Failed to update Raydium cache:", err); + } +} + +app.get("/api/v1/defi/raydium/yields", async (c) => { + // Update cache if older than 60 seconds + if (Date.now() - raydiumCache.lastUpdated > 60_000) { + await updateRaydiumCache(); + } + + return c.json({ + source: "raydium-cache", + lastUpdated: new Date(raydiumCache.lastUpdated).toISOString(), + pools: raydiumCache.data + }); +}); +``` + +--- + +## 5. Meteora DLMM Active Bins Endpoint + +Monetizes Meteora DLMM pool bin details. Bin distributions represent highly valuable execution path data for routing engines. + +```typescript +import { DLMM } from "@meteora-ag/dlmm"; + +app.get("/api/v1/defi/meteora/bins", async (c) => { + const poolAddress = c.req.query("pool"); + if (!poolAddress) { + return c.json({ error: "Missing 'pool' parameter" }, 400); + } + + try { + const connection = new (await import("@solana/web3.js")).Connection(SOLANA_RPC_URL); + const poolPubKey = new PublicKey(poolAddress); + + // Load DLMM Pool + const dlmmPool = await DLMM.create(connection, poolPubKey); + const activeBin = await dlmmPool.getActiveBin(); + + // Fetch bins around the active bin + const bins = await dlmmPool.getBinsAroundActiveBin(10, 10); + + return c.json({ + poolAddress, + activeBinId: activeBin.binId, + activePrice: activeBin.price, + bins: bins.map(b => ({ + binId: b.binId, + xAmount: b.xAmount.toString(), + yAmount: b.yAmount.toString(), + price: b.price + })) + }); + } catch (error: any) { + return c.json({ error: `DLMM bin fetch failed: ${error.message}` }, 500); + } +}); +``` + +--- + +## 6. Drift Perp Position & PnL Gated Endpoint + +Integrates `@drift-labs/sdk` to fetch perpetual market position metrics for specific wallets behind an x402 barrier. + +```typescript +import { DriftClient, Wallet, BulkAccountLoader } from "@drift-labs/sdk"; + +app.get("/api/v1/defi/drift/perp-pnl", async (c) => { + const userAddress = c.req.query("user"); + if (!userAddress) { + return c.json({ error: "Missing 'user' query parameter" }, 400); + } + + try { + const connection = new (await import("@solana/web3.js")).Connection(SOLANA_RPC_URL); + const userPubKey = new PublicKey(userAddress); + + // Initialize read-only Drift client + const driftClient = new DriftClient({ + connection, + wallet: new Wallet(new (await import("@solana/web3.js")).Keypair()), // Dummy keypair + env: "mainnet-beta" + }); + + await driftClient.subscribe(); + + // Fetch user account and positions + const user = driftClient.getUser(userPubKey); + await user.subscribe(); + + const activePositions = user.getActivePerpPositions(); + const unrealizedPnL = user.getUnrealizedPNL(); + + // Cleanup subscription + await user.unsubscribe(); + await driftClient.unsubscribe(); + + return c.json({ + userAddress, + unrealizedPnL: unrealizedPnL.toString(), + positions: activePositions.map(p => ({ + marketIndex: p.marketIndex, + baseAssetAmount: p.baseAssetAmount.toString(), + quoteAssetAmount: p.quoteAssetAmount.toString(), + quoteEntryAmount: p.quoteEntryAmount.toString(), + })) + }); + } catch (error: any) { + return c.json({ error: `Drift fetch failed: ${error.message}` }, 500); + } +}); +``` diff --git a/skill/references/x402-facilitator.md b/skill/references/x402-facilitator.md new file mode 100644 index 0000000..655ca12 --- /dev/null +++ b/skill/references/x402-facilitator.md @@ -0,0 +1,178 @@ +# x402 Facilitators & Verification Networks + +Facilitators verify and settle x402 payment payloads, relieving sellers of the need to parse raw Solana transaction logs or query RPC node validation manually. Use this reference to configure, integrate, and deploy hosted or self-hosted x402 facilitators. + +--- + +## 1. Protocol Architecture & Flow + +The facilitator acts as a trusted verification middleware or settlement oracle between the client, the seller server, and the blockchain network. + +```text +Client -> Server: request protected resource +Server -> Client: 402 payment requirements +Client -> Solana: sign/broadcast payment transaction +Client -> Server: retry request with x402 payment headers (X-Payment-Txid, etc.) +Server -> Facilitator: verify payment (checks tx exists, paid to payee, correct USDC/asset/amount) +Facilitator -> Server: returns verified payload +Server -> Client: resource + PAYMENT-RESPONSE receipt header +``` + +For Solana, the facilitator operates using the `exact` payment scheme via the `@x402/svm` engine. + +--- + +## 2. Hosted Facilitator Integration + +The official hosted facilitator handles settlement verification dynamically. Keep the endpoints configurable via environment variables. + +### Environment Configuration +```env +X402_FACILITATOR_URL=https://x402.org/facilitator +X402_FACILITATOR_API_KEY=your_secured_api_key +``` + +### Manual Verification via REST (Fallback Pattern) +If you are not using framework-specific x402 middleware, you can verify payments manually by making a POST request to the facilitator endpoint: + +```typescript +interface FacilitatorVerifyResponse { + verified: boolean; + network: string; + txid: string; + payee: string; + amountAtomic: string; + asset: string; + timestamp: number; +} + +/** + * Manually queries the facilitator to verify an x402 payment + */ +export async function verifyPaymentWithFacilitator( + txid: string, + expectedAmount: bigint, + expectedPayee: string, + expectedAsset: string +): Promise { + const url = `${process.env.X402_FACILITATOR_URL || "https://x402.org/facilitator"}/verify`; + const apiKey = process.env.X402_FACILITATOR_API_KEY; + + try { + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + ...(apiKey ? { "Authorization": `Bearer ${apiKey}` } : {}) + }, + body: JSON.stringify({ + txid, + expectedAmount: expectedAmount.toString(), + expectedPayee, + expectedAsset + }) + }); + + if (!response.ok) { + console.error(`Facilitator verification returned status ${response.status}`); + return false; + } + + const data = (await response.json()) as FacilitatorVerifyResponse; + return data.verified; + } catch (error) { + console.error("Facilitator query failed:", error); + return false; + } +} +``` + +--- + +## 3. Self-Hosted Facilitator Configuration + +For high-volume production use cases or applications with strict privacy compliance, you should self-host the facilitator service. + +### Checklist: +- **Private Solana RPC**: Avoid public RPC endpoints which can fail under load or rate limits. +- **Dedicated Fee Payer Signer**: Isolated keypair with a small SOL balance to pay for transaction polling or signature confirmation queries. +- **Settlement Receipt Caching**: Store payment status in a high-speed database or Redis to prevent double-spending checks from overloading the Solana RPC. +- **Network Rate Limits**: Implement API rate limits to prevent denial-of-service (DoS) attacks on verification endpoints. + +### Self-Hosted Express/Hono Setup with Redis Caching +Below is an implementation of a basic self-hosted verification handler with Redis caching to avoid repeating RPC queries. + +```typescript +import { Hono } from "hono"; +import { createSolanaRpc, Address } from "@solana/kit"; +import { createClient } from "redis"; + +const app = new Hono(); +const rpc = createSolanaRpc(process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com"); +const redis = createClient({ url: process.env.REDIS_URL || "redis://localhost:6379" }); + +await redis.connect(); + +app.post("/verify", async (c) => { + const { txid, expectedAmount, expectedPayee, expectedAsset } = await c.req.json(); + + if (!txid || !expectedAmount || !expectedPayee || !expectedAsset) { + return c.json({ error: "Missing required fields" }, 400); + } + + // 1. Check Redis Cache + const cachedStatus = await redis.get(`tx:${txid}`); + if (cachedStatus === "verified") { + return c.json({ verified: true, source: "cache" }); + } + + try { + // 2. Query Solana blockchain for transaction details + const txInfo = await rpc.getTransaction(txid, { + maxSupportedTransactionVersion: 0, + encoding: "jsonParsed" + }).send(); + + if (!txInfo || !txInfo.value || txInfo.value.meta?.err) { + return c.json({ verified: false, error: "Transaction not found or failed on-chain" }); + } + + // 3. Verify transfer amounts (Token Balance Change Analysis) + // Simple mock logic: in production, parse the innerInstructions or balance changes + const isValid = await validateBalanceChanges(txInfo.value, expectedAmount, expectedPayee, expectedAsset); + + if (isValid) { + // Cache the result for 24 hours to prevent replay checks + await redis.setEx(`tx:${txid}`, 86400, "verified"); + return c.json({ verified: true, source: "rpc" }); + } + + return c.json({ verified: false, error: "Payment details mismatch" }); + } catch (error: any) { + return c.json({ verified: false, error: error.message }, 500); + } +}); + +async function validateBalanceChanges( + tx: any, + amount: string, + payee: string, + asset: string +): Promise { + // Parsing instructions and balance adjustments for exact payment verification + return true; +} +``` + +--- + +## 4. Operational Best Practices & Troubleshooting + +### RPC Load Balancing +Always configure fallback RPC endpoints. If your facilitator experiences rate limiting, it will fail to verify valid user transactions, causing request drops. + +### Signer Key Rotation +When self-hosting a facilitator with transaction writing capabilities (e.g. batching or auto-renewing leases), rotate fee-payer keys quarterly and monitor gas depletion. + +### Resolution Timeouts +Set connection timeouts on facilitator requests to 3000ms. If the facilitator is unresponsive, fall back to checking on-chain RPC logs directly (or fail open/close based on risk policy). diff --git a/skill/references/x402-mcp-monetization.md b/skill/references/x402-mcp-monetization.md new file mode 100644 index 0000000..b61c494 --- /dev/null +++ b/skill/references/x402-mcp-monetization.md @@ -0,0 +1,215 @@ +# Monetizing MCP Servers with HTTP 402 + +Use this reference to implement an x402-paid HTTP gateway in front of Model Context Protocol (MCP) servers, supporting per-tool pricing, streaming/chunk billing, batch call discounting, and capability advertisements. + +--- + +## 1. Architecture Overview + +To monetize MCP tools, gate the HTTP transport layer (SSE or custom HTTP routes) rather than gating the local stdio server directly. + +```text +Agent MCP Client -> x402 HTTP Gateway -> MCP Server + <- 402 challenge +Agent pays with @x402/fetch +Agent retries call -> gateway forwards JSON-RPC/tool call +``` + +--- + +## 2. Gating Tool Calls + +```typescript +import { Hono } from "hono"; +import { paymentMiddleware } from "@x402/hono"; +import { ExactSvmScheme } from "@x402/svm"; +import { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; + +const app = new Hono(); + +const priceByTool: Record = { + "summarize": "10000", // 0.01 USDC + "research": "50000", // 0.05 USDC +}; + +app.use( + "/mcp/v1/tools/call", + paymentMiddleware({ + accepts: [ + { + scheme: ExactSvmScheme.scheme, + network: process.env.X402_NETWORK ?? "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + maxAmountRequired: "50000", + payTo: process.env.PAYEE_WALLET!, + asset: process.env.USDC_MINT, + maxAgeSeconds: 60, + }, + ], + description: "Paid access to MCP tool execution.", + }) +); + +app.post("/mcp/v1/tools/call", async (c) => { + const idempotencyKey = c.req.header("Idempotency-Key"); + if (!idempotencyKey) { + return c.json({ error: "Idempotency-Key required" }, 428); + } + + const body = await c.req.json(); + if (!Object.hasOwn(priceByTool, body.name)) { + return c.json({ error: "Unknown or unpriced tool" }, 400); + } + + const client = new Client({ name: "x402-gateway", version: "1.0.0" }, {}); + const transport = new SSEClientTransport(new URL("http://localhost:8080/sse")); + await client.connect(transport); + + const result = await client.callTool({ + name: body.name, + arguments: body.arguments, + }); + + return c.json(result); +}); +``` + +--- + +## 3. Streaming Tool Call & Chunk Billing + +For tools that stream long-running responses (e.g. detailed research summaries, code generation), charging a static fee upfront might undercharge or overcharge the client. Implement a stream-metering system that charges per SSE chunk or per-token returned. + +```typescript +app.post("/mcp/v1/tools/call/stream", async (c) => { + const body = await c.req.json(); + const baseFee = 5000n; // 0.005 USDC base fee + + // Set headers for server-sent events (SSE) + c.header("Content-Type", "text/event-stream"); + c.header("Cache-Control", "no-cache"); + c.header("Connection", "keep-alive"); + + // Fetch the tool stream from downstream MCP server + // ... (Connect to MCP Server and acquire stream) + + return c.stream(async (stream) => { + let tokensSent = 0; + + // Simulate reading chunks from MCP stream + for (let i = 0; i < 5; i++) { + const chunk = `data: { "text": "Research update ${i}...\\n" }\n\n`; + await stream.write(chunk); + tokensSent += 10; + await stream.sleep(100); + } + + // Compute final cost: Base fee + micro-lamports per token + const tokenFee = BigInt(tokensSent) * 50n; // 50 atomic units per token + const totalCost = baseFee + tokenFee; + + // Send final transaction billing info in the stream metadata + await stream.write(`data: { "billing": { "totalCostAtomicUsdc": "${totalCost.toString()}" } }\n\n`); + }); +}); +``` + +--- + +## 4. Batch Tool Call Pricing & Discounts + +When an agent executes multiple tools simultaneously, you can reduce settlement overhead by allowing the client to send a batch request and offering a discount. + +```typescript +interface BatchCallRequest { + tools: Array<{ name: string; arguments: any }>; +} + +app.post("/mcp/v1/tools/batch", async (c) => { + const body = (await c.req.json()) as BatchCallRequest; + + // Calculate total gross cost + let totalCostAtomic = 0n; + for (const t of body.tools) { + const toolCost = BigInt(priceByTool[t.name] || "0"); + totalCostAtomic += toolCost; + } + + // Apply batch discount: 15% off for 3 or more tools + if (body.tools.length >= 3) { + totalCostAtomic = (totalCostAtomic * 85n) / 100n; + console.log(`[Batch Discount] Applied 15% discount. New total: ${totalCostAtomic}`); + } + + // Enforce x402 payment validation for the calculated totalCostAtomic + // ... (Execute payment verification) + + // Execute all tools concurrently + const client = new Client({ name: "x402-batch-gateway", version: "1.0.0" }, {}); + // ... (Connect to MCP, call tools in parallel via Promise.all) + + return c.json({ results: ["Batch results mock..."] }); +}); +``` + +--- + +## 5. Paid Tool Capability Advertisement + +To ensure that autonomous planner agents understand the cost of a tool *before* invoking it, extend the MCP standard `listTools` schema. Add a custom `metadata` or `annotations` block containing payment details. + +```typescript +app.get("/mcp/v1/tools/list", (c) => { + return c.json({ + tools: [ + { + name: "summarize", + description: "Summarizes text documents. Premium service.", + inputSchema: { + type: "object", + properties: { + text: { type: "string" } + }, + required: ["text"] + }, + // Custom x402 monetization annotations + monetization: { + scheme: "exact", + priceAtomicUsdc: "10000", // 0.01 USDC + payee: process.env.PAYEE_WALLET!, + network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" + } + }, + { + name: "research", + description: "Performs real-time search on Solana block data.", + inputSchema: { + type: "object", + properties: { + query: { type: "string" } + }, + required: ["query"] + }, + monetization: { + scheme: "exact", + priceAtomicUsdc: "50000", // 0.05 USDC + payee: process.env.PAYEE_WALLET!, + network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" + } + } + ] + }); +}); +``` + +--- + +## 6. Local Devnet Integration Testing + +To test the monetized MCP gateway locally using Solana Devnet: + +1. Deploy the gateway server using Devnet constants: + - Network: `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` + - USDC Mint: `4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU` +2. Bootstrap a test buyer wallet using the faucet helper script to acquire Devnet SOL and USDC. +3. Configure the buyer agent's MCP client wrapper to intercept tool requests, check the `monetization` metadata, verify its local spend policy allows the price, and execute the payment using `@x402/fetch` before forwarding. diff --git a/skill/references/x402-multi-agent.md b/skill/references/x402-multi-agent.md new file mode 100644 index 0000000..5f9bc97 --- /dev/null +++ b/skill/references/x402-multi-agent.md @@ -0,0 +1,236 @@ +# Multi-Agent Commerce & Trust Delegation + +Use this reference to implement agent-to-agent (M2M) payment architectures, including service registries, orchestrator-worker patterns, spend delegation, and cost accounting. + +--- + +## 1. Service Registry & Discovery + +To pay each other, agents need to discover what services exist and their pricing. A service registry publishes a JSON manifest containing the agent endpoint, description, capabilities, network, asset, and pricing details. + +### JSON Manifest Schema (`agent-service.json`) +```json +{ + "agentId": "solana-translator-agent", + "endpoint": "https://translate.agent.network", + "version": "1.0.0", + "payment": { + "network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", + "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + "payee": "Merch1111111111111111111111111111111111111", + "pricing": { + "GET /translate": { + "scheme": "exact", + "amount": "5000" + } + } + } +} +``` + +--- + +## 2. Orchestrator-Worker Payment Flow + +In this pattern, an **Orchestrator Agent** acts as a client that delegates subtasks to specialized **Worker Agents**. The Worker Agents gate their API routes behind x402, requiring the Orchestrator to pay in USDC. + +```typescript +import { wrapFetchWithPayment } from "@x402/fetch"; +import { createSvmClient } from "@x402/svm/client"; +import { toClientSvmSigner } from "@x402/svm"; +import { createKeyPairSignerFromBytes } from "@solana/kit"; +import { base58 } from "@scure/base"; + +/** + * Orchestrator calls a paid worker agent using the x402 fetch wrapper + */ +export async function callWorkerAgent( + workerUrl: string, + payload: any, + orchestratorPrivateKey: string, + rpcUrl: string +): Promise { + const keypair = await createKeyPairSignerFromBytes( + base58.decode(orchestratorPrivateKey) + ); + + const client = createSvmClient({ + signer: toClientSvmSigner(keypair), + rpcUrl + }); + + const paidFetch = wrapFetchWithPayment(fetch, client); + + console.log(`[Orchestrator] Calling paid worker agent at: ${workerUrl}`); + const response = await paidFetch(workerUrl, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Idempotency-Key": crypto.randomUUID() + }, + body: JSON.stringify(payload) + }); + + if (!response.ok) { + throw new Error(`Worker agent rejected request with status ${response.status}`); + } + + const receiptHeader = response.headers.get("PAYMENT-RESPONSE"); + console.log(`[Orchestrator] Received payment confirmation receipt: ${receiptHeader}`); + + return response.json(); +} +``` + +--- + +## 3. Trust & Spend Delegation + +When an Orchestrator spawns a Sub-Agent, it should never share its primary private key. Instead, the Orchestrator delegates a limited spending policy to the Sub-Agent. + +### Spending Policy Schema for Sub-Agents + +```typescript +export interface SubAgentSpendPolicy { + subAgentPublicKey: string; + maxAtomicUsdcPerCall: bigint; + totalSessionBudgetAtomicUsdc: bigint; + expirationTimestamp: number; +} + +export class SpendDelegationGuard { + private policy: SubAgentSpendPolicy; + private currentSpent: bigint = 0n; + + constructor(policy: SubAgentSpendPolicy) { + this.policy = policy; + } + + /** + * Asserts if the sub-agent is authorized to spend the requested amount + */ + public checkSpendAuthorization(requestedAmount: bigint): void { + if (Date.now() > this.policy.expirationTimestamp) { + throw new Error("[SPEND DENIED] Spend delegation session has expired."); + } + + if (requestedAmount > this.policy.maxAtomicUsdcPerCall) { + throw new Error(`[SPEND DENIED] Requested amount ${requestedAmount} exceeds per-call cap of ${this.policy.maxAtomicUsdcPerCall}`); + } + + if (this.currentSpent + requestedAmount > this.policy.totalSessionBudgetAtomicUsdc) { + throw new Error(`[SPEND DENIED] Session budget exceeded. Spent: ${this.currentSpent}, Requested: ${requestedAmount}, Budget: ${this.policy.totalSessionBudgetAtomicUsdc}`); + } + } + + /** + * Commits the spent amount after a successful payment + */ + public recordSpend(amount: bigint): void { + this.currentSpent += amount; + } +} +``` + +--- + +## 4. Multi-Hop Cost Accounting + +In a multi-hop pipeline (e.g. Orchestrator -> Researcher Agent -> Translator Agent), the total budget must be tracked across the entire chain to prevent budget exhaustion. + +To achieve this, the Orchestrator passes a tracking header (`X-Session-Budget-Trace`) that lists the remaining budget and the spending chain. + +```typescript +interface BudgetTrace { + sessionId: string; + originalBudgetAtomic: string; + remainingBudgetAtomic: string; + hopCount: number; +} + +/** + * Middleware for Worker Agents to parse and enforce multi-hop budget headers + */ +export function enforceTraceBudget(maxHopLimit = 5) { + return async (c: any, next: any) => { + const traceHeader = c.req.header("X-Session-Budget-Trace"); + + if (traceHeader) { + const trace = JSON.parse(traceHeader) as BudgetTrace; + + if (trace.hopCount >= maxHopLimit) { + return c.json({ error: "Max multi-hop limit exceeded" }, 400); + } + + const remaining = BigInt(trace.remainingBudgetAtomic); + if (remaining <= 0n) { + return c.json({ error: "Distributed session budget fully exhausted" }, 403); + } + } + + await next(); + }; +} +``` + +--- + +## 5. Bidding & Competing Marketplaces + +Orchestrator agents can query multiple workers offering the same capability to find the cheapest service. + +```typescript +interface Bid { + agentEndpoint: string; + priceAtomicUsdc: bigint; + estimatedLatencyMs: number; +} + +export async function queryBidsForTask( + candidateEndpoints: string[] +): Promise { + const bids: Bid[] = []; + + for (const endpoint of candidateEndpoints) { + try { + const startTime = Date.now(); + // Fetch the manifest or query the price of the endpoint + const response = await fetch(`${endpoint}/manifest`); + if (response.ok) { + const manifest = await response.json(); + const price = BigInt(manifest.payment.pricing["POST /task"].amount); + + bids.push({ + agentEndpoint: endpoint, + priceAtomicUsdc: price, + estimatedLatencyMs: Date.now() - startTime + }); + } + } catch (err) { + console.warn(`Failed to retrieve bid from: ${endpoint}`); + } + } + + if (bids.length === 0) return null; + + // Sort by price ascending, then latency ascending + bids.sort((a, b) => { + if (a.priceAtomicUsdc !== b.priceAtomicUsdc) { + return a.priceAtomicUsdc < b.priceAtomicUsdc ? -1 : 1; + } + return a.estimatedLatencyMs - b.estimatedLatencyMs; + }); + + return bids[0]; // Returns the cheapest, lowest latency bid +} +``` + +--- + +## 6. Price-Inflation & Sybil Attack Defenses + +To prevent malicious sub-agents or worker proxies from artificially inflating transaction pricing: + +1. **Signed Price Quotes**: Workers must sign their payment challenges. The buyer agent verifies that the price was signed by the registered provider public key within the last `maxAgeSeconds`. +2. **Replay Cache**: Buyer agents must cache the transaction IDs of settled payments locally to avoid double-paying for the same challenge. +3. **Payee Allowlist**: Buyer agents must verify the payee's public key against a list of known service providers before signing the transaction payload. diff --git a/skill/references/x402-security.md b/skill/references/x402-security.md new file mode 100644 index 0000000..d659f08 --- /dev/null +++ b/skill/references/x402-security.md @@ -0,0 +1,201 @@ +# x402 Security, Key Vaulting, and Spending Caps + +Security is paramount in agentic workflows. Because agents sign transactions using private keys, builders must enforce strict security boundaries. Use this reference to implement robust security checks, OFAC compliance, gas drain mitigations, Token-2022 validations, durable nonces, and prompt injection defenses. + +--- + +## 1. KMS Key Management + +Never store private keys in plaintext `.env` files or raw database records. Use Key Management Services (KMS) like AWS KMS, Google Cloud KMS, or HashiCorp Vault. + +### Pattern: Remote Signature Requests +Instead of giving the agent a raw private key, have the agent request a signature from a secure, isolated microservice that enforces policies. + +``` ++------------+ 1. SignRequest (Tx, Amount) +---------------------+ +| | --------------------------------------> | Secure Sign Service | +| AI Agent | | - Checks budget | +| | <------ 2. Signed Transaction ---------- | - Decrypts KMS key | ++------------+ +---------------------+ +``` + +--- + +## 2. Spending Thresholds & Cooldowns + +Implement cooldown periods and hard maximum spending thresholds to protect against runaway agent loops. + +### Spending Safety Manager Checklist: +- **Per-Transaction Cap**: Maximum USDC amount allowed for a single 402 challenge. +- **Daily/Weekly Budget**: Global limits across all transactions in a rolling window. +- **Rate Limiting (Cooldowns)**: Enforce a minimum interval between payments (e.g., maximum 1 payment every 10 seconds). +- **Manual Approval Threshold**: Any transaction above a certain amount (e.g., $1.00 USDC) requires human-in-the-loop approval. +- **Domain Allowlist**: Only pay hosts that the user or application explicitly trusts. +- **Network Allowlist**: Only pay expected CAIP-2 IDs such as `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` for devnet. +- **Payee Allowlist**: Match the seller wallet against a known allowlist when possible. +- **Receipt Log**: Persist `PAYMENT-RESPONSE` with request ID, route, amount, payee, network, and timestamp. + +--- + +## 3. OFAC Screening Compliance + +Autonomous agents must comply with financial regulations, including OFAC sanctions. Check target wallets against known sanctioned addresses before signing. + +```typescript +import { Address } from "@solana/kit"; + +// Hardcoded sample list of prohibited/sanctioned wallets (e.g. OFAC SDN list entries) +const SANCTIONED_WALLETS = new Set([ + "11111111111111111111111111111111", // Prohibited + "9w8P358E2Ugz74Kx1B2n7zZ27H2K3Wv4", // Mock Sanctioned Address +]); + +/** + * Validates payee wallet address against sanction lists + */ +export function assertOfacCompliance(payeeAddress: string): void { + if (SANCTIONED_WALLETS.has(payeeAddress)) { + throw new Error(`[OFAC BLOCKED] Transfer to sanctioned address is prohibited: ${payeeAddress}`); + } +} +``` + +--- + +## 4. Gas Fee Drain Attack Prevention + +Malicious actors or buggy sellers can exploit an agent by requesting transactions that specify exorbitant priority fees, draining the agent's SOL balance. + +### Defense: Enforce Compute Budget Caps +When signing or sending transactions, inspect and override the transaction's compute budget instructions: + +```typescript +import { + addTransactionInstruction, + createDefaultTransaction, + signTransaction +} from "@solana/kit"; + +// Gas Guardrail Limits +const MAX_PRIORITY_FEE_LAMPORTS = 100_000n; // Cap priority fee per tx at 0.0001 SOL +const MAX_COMPUTE_UNIT_PRICE = 500_000n; // Micro-lamports per CU limit + +/** + * Safely adds priority fee instructions with a strict upper cap + */ +export function enforceComputeBudgetCaps( + transaction: any, + computeUnits: number, + microLamportsPerCU: bigint +): any { + const safeCUPrice = microLamportsPerCU > MAX_COMPUTE_UNIT_PRICE + ? MAX_COMPUTE_UNIT_PRICE + : microLamportsPerCU; + + // Add standard ComputeBudget instructions to override transaction fees + const setCuLimitIx = { + programId: "ComputeBudget111111111111111111111111111111" as any, + keys: [], + data: Buffer.from([0, ...writeInt(computeUnits)]) // SetComputeUnitLimit + }; + + const setCuPriceIx = { + programId: "ComputeBudget111111111111111111111111111111" as any, + keys: [], + data: Buffer.from([3, ...writeBigInt(safeCUPrice)]) // SetComputeUnitPrice + }; + + let updatedTx = addTransactionInstruction(setCuLimitIx, transaction); + updatedTx = addTransactionInstruction(setCuPriceIx, updatedTx); + return updatedTx; +} + +function writeInt(val: number): Uint8Array { + const buf = new ArrayBuffer(4); + new DataView(buf).setUint32(0, val, true); + return new Uint8Array(buf); +} + +function writeBigInt(val: bigint): Uint8Array { + const buf = new ArrayBuffer(8); + new DataView(buf).setBigUint64(0, val, true); + return new Uint8Array(buf); +} +``` + +--- + +## 5. Token-2022 Transfer Fee Validation + +Some SPL Token-2022 mints employ a **Transfer Fee** extension. If an agent pays with a Token-2022 token, it must calculate the net transfer output to ensure the seller receives the exact requested amount *after* fees, without exceeding the agent's absolute spending cap. + +```typescript +import { Address } from "@solana/kit"; + +interface Token2022TransferFeeConfig { + feeBasisPoints: number; + maximumFee: bigint; +} + +/** + * Calculates total gross amount required to ensure recipient receives expectedAmount + */ +export function calculateToken2022GrossAmount( + expectedAmount: bigint, + feeConfig: Token2022TransferFeeConfig +): bigint { + const bps = BigInt(feeConfig.feeBasisPoints); + const maxFee = feeConfig.maximumFee; + + // Expected fee = expectedAmount * bps / 10000 + let calculatedFee = (expectedAmount * bps) / 10000n; + if (calculatedFee > maxFee) { + calculatedFee = maxFee; + } + + const grossAmount = expectedAmount + calculatedFee; + return grossAmount; +} +``` + +--- + +## 6. Durable Nonces for Network Congestion + +When the Solana network experiences heavy congestion, transactions signed using standard recent blockhashes can expire before confirmation (approx. 60-90 seconds). This leads to a race condition where the agent might retry and double-pay. + +**Solution**: High-frequency agents should create a **Durable Nonce Account**. A transaction signed with a durable nonce has an indefinite lifespan, allowing safe retries without the risk of double-spending. + +```typescript +// Durable Nonce instruction pattern using @solana/kit +import { Address } from "@solana/kit"; + +interface NonceTxParams { + nonceAccount: Address; + nonceValue: string; // From getAccountInfo for nonce account + authorizedSigner: Address; +} + +export function buildNonceInstruction(params: NonceTxParams) { + return { + programId: "11111111111111111111111111111111" as Address, // System Program + keys: [ + { pubkey: params.nonceAccount, isSigner: false, isWritable: true }, + { pubkey: "SysvarRecentBlockHashes11111111111111111111" as Address, isSigner: false, isWritable: false }, + { pubkey: params.authorizedSigner, isSigner: true, isWritable: false } + ], + data: Buffer.from([4]) // AdvanceNonceAccount instruction discriminator + }; +} +``` + +--- + +## 7. LLM Prompt Injection Defenses + +If your agent takes user prompts directly, malicious inputs might attempt to trick the agent into paying arbitrary wallets or increasing spending limits. + +### Hardening Strategies: +1. **Payee Allowlist Enforcement**: Perform check validation outside the LLM execution context. The runtime code must intercept all `paidFetch` calls and validate the payee's Address against a static/verified database. +2. **Strict Parser Validation**: Never allow the LLM to write base58 private keys or call signing methods directly. Gated actions must go through the spending manager. +3. **Structured Outputs**: Require the LLM to output a structured JSON plan (rather than running raw scripts). The plan is validated by a secure schema parser before executing on-chain actions. diff --git a/skill/references/x402-server-patterns.md b/skill/references/x402-server-patterns.md new file mode 100644 index 0000000..75657b4 --- /dev/null +++ b/skill/references/x402-server-patterns.md @@ -0,0 +1,106 @@ +# x402 Server Integration Patterns + +Use this reference when protecting HTTP endpoints with x402 payment requirements settled on Solana USDC. + +## Defaults + +```typescript +const SOLANA_MAINNET = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"; +const SOLANA_DEVNET = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"; +const USDC_MAINNET = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; +const USDC_DEVNET = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"; +``` + +Use `exact` for Solana/SVM x402 payments. Do not use `solana-usdc` or `solana:mainnet` in v2 examples. + +## Express route gate + +Use the framework middleware from `@x402/express` and bind every payment requirement tightly to the route. + +```typescript +import express from "express"; +import { paymentMiddleware } from "@x402/express"; +import { ExactSvmScheme } from "@x402/svm"; + +const app = express(); + +const network = process.env.X402_NETWORK ?? "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"; +const payTo = process.env.PAYEE_WALLET!; + +app.use( + paymentMiddleware({ + "POST /api/v1/generate": { + accepts: [ + { + scheme: ExactSvmScheme.scheme, + network, + maxAmountRequired: "50000", // 0.05 USDC in atomic units when supported by middleware + payTo, + asset: process.env.USDC_MINT, + maxAgeSeconds: 60, + }, + ], + description: "AI image generation endpoint.", + }, + }) +); + +app.post("/api/v1/generate", (req, res) => { + if (!req.header("Idempotency-Key")) { + return res.status(428).json({ error: "Idempotency-Key required" }); + } + + res.json({ image: "data:image/png;base64,..." }); +}); +``` + +If your installed middleware expects a different field name such as `resource` instead of `payTo`/`asset`, map the same values without changing the security model: exact network, exact asset, exact payee, exact method/route, and short expiry. + +## Hono route gate + +```typescript +import { Hono } from "hono"; +import { paymentMiddleware } from "@x402/hono"; +import { ExactSvmScheme } from "@x402/svm"; + +const app = new Hono(); + +app.use( + "/api/v1/translate", + paymentMiddleware({ + accepts: [ + { + scheme: ExactSvmScheme.scheme, + network: process.env.X402_NETWORK ?? "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + maxAmountRequired: "1000", + payTo: process.env.PAYEE_WALLET!, + asset: process.env.USDC_MINT, + maxAgeSeconds: 60, + }, + ], + description: "Premium translation service.", + }) +); + +app.post("/api/v1/translate", (c) => { + if (!c.req.header("Idempotency-Key")) { + return c.json({ error: "Idempotency-Key required" }, 428); + } + + return c.json({ translatedText: "..." }); +}); +``` + +## Next.js route handlers + +Prefer official `@x402/next` helpers/middleware for Next.js. Do not hand-roll `PAYMENT-REQUIRED`, `X-PAYMENT`, or on-chain verification logic in route handlers unless the installed SDK requires it. + +Minimum server checks: + +- route and HTTP method are exact +- `network` is a v2 CAIP-2 ID +- `asset` is the expected USDC mint +- `payTo` is the expected wallet +- `maxAmountRequired` is in the expected unit for the installed middleware +- `maxAgeSeconds` is short, usually 60 seconds +- mutating methods require `Idempotency-Key` diff --git a/skill/references/x402-solana-integration.md b/skill/references/x402-solana-integration.md new file mode 100644 index 0000000..9deeb95 --- /dev/null +++ b/skill/references/x402-solana-integration.md @@ -0,0 +1,210 @@ +# Solana Integration & SPL USDC Settlement + +Use this reference for Solana network IDs, USDC mints, signers, settlement safety, Associated Token Accounts (ATA), Token-2022 detections, durable nonces, and compute budget overrides. + +--- + +## 1. Network and USDC Constants + +Use x402 v2 CAIP-2 network IDs. Do not use v1 shorthand values like `solana:mainnet` in x402 v2 examples. + +| Network | CAIP-2 ID | USDC Mint Address | Decimals | +| :--- | :--- | :--- | :--- | +| **Mainnet-Beta** | `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` | 6 | +| **Devnet** | `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` | `4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU` | 6 | +| **Testnet** | `solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z` | `4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU` | 6 | + +--- + +## 2. Client Signer Setup + +`@x402/svm` v2 uses Solana Kit signers. Load secrets from a local development secret or KMS, then convert the signer for x402. + +```typescript +import { createSvmClient } from "@x402/svm/client"; +import { toClientSvmSigner } from "@x402/svm"; +import { createKeyPairSignerFromBytes } from "@solana/kit"; +import { base58 } from "@scure/base"; + +const keypair = await createKeyPairSignerFromBytes( + base58.decode(process.env.SVM_PRIVATE_KEY!) +); + +const client = createSvmClient({ + signer: toClientSvmSigner(keypair), + rpcUrl: process.env.SOLANA_RPC_URL, +}); +``` + +Use base58 secrets for local development. In production, load the signer from KMS/HSM or a wallet service. Never commit raw secret-key arrays. + +--- + +## 3. Server Verification + +Prefer official x402 middleware/facilitator verification over hand-rolled Solana RPC polling. The server should validate the payment requirement it issued: +- Method and route binding +- CAIP-2 network matching +- USDC mint / asset validation +- Exact payee checking +- Max amount checking in atomic USDC units +- Quote expiry / `maxAgeSeconds` enforcement +- Idempotency key validation for mutating routes + +--- + +## 4. Associated Token Account (ATA) Existence Checks + +Before initiating an SPL token transfer to settle an x402 requirement, verify if the recipient's Associated Token Account (ATA) exists. Sending a token transfer to a non-existent ATA will cause the transaction to fail. If it is missing, create it first using the `createAssociatedTokenAccountInstruction` helper. + +```typescript +import { Address, createSolanaRpc } from "@solana/kit"; +import { getAssociatedTokenAddressSync, createAssociatedTokenAccountInstruction } from "@solana/spl-token"; +import { PublicKey } from "@solana/web3.js"; + +/** + * Asserts if ATA exists, returning transaction instruction to create it if it doesn't + */ +export async function getOrCreateAtaInstructionIfNeeded( + rpcUrl: string, + walletAddress: string, + tokenMintAddress: string, + payerAddress: string +): Promise { + const rpc = createSolanaRpc(rpcUrl); + + const walletPubKey = new PublicKey(walletAddress); + const mintPubKey = new PublicKey(tokenMintAddress); + const payerPubKey = new PublicKey(payerAddress); + + // 1. Calculate ATA Address + const ataAddress = getAssociatedTokenAddressSync( + mintPubKey, + walletPubKey, + true // Allow owner off-curve (e.g. PDAs) + ); + + try { + // 2. Fetch account info to verify existence + const accountInfo = await rpc.getAccountInfo(ataAddress.toBase58() as Address).send(); + + // If account exists, no creation instruction needed + if (accountInfo && accountInfo.value !== null) { + return null; + } + } catch (error) { + console.log("ATA does not exist. Formatting creation instruction..."); + } + + // 3. Construct creation instruction + const creationInstruction = createAssociatedTokenAccountInstruction( + payerPubKey, + ataAddress, + walletPubKey, + mintPubKey + ); + + return creationInstruction; +} +``` + +--- + +## 5. Token-2022 Detection & Extension Checks + +If the asset mint utilizes the newer Token-2022 standard, you must inspect the mint's extensions to see if additional fees (like transfer fee hooks) will be applied. + +```typescript +import { createSolanaRpc, Address } from "@solana/kit"; + +// Token-2022 Program ID Address +const TOKEN_2022_PROGRAM_ID = "TokenzQdBNbLqP5xxaAkJ7yyWjLMzXJqUPPStVEtC2"; + +/** + * Checks if a mint is managed by Token-2022 program and lists its extensions + */ +export async function getMintProgramAndExtensions( + rpcUrl: string, + mintAddress: Address +): Promise<{ program: string; isToken2022: boolean; extensions: string[] }> { + const rpc = createSolanaRpc(rpcUrl); + + const accountInfo = await rpc.getAccountInfo(mintAddress).send(); + if (!accountInfo || !accountInfo.value) { + throw new Error("Mint account not found."); + } + + const ownerProgram = accountInfo.value.owner; + const isToken2022 = ownerProgram === TOKEN_2022_PROGRAM_ID; + const extensions: string[] = []; + + if (isToken2022) { + // Deserialize mint layout to find extension types + const rawData = accountInfo.value.data; + // Inspect byte layout for extension presence (e.g., Transfer Fee, Mint Close Authority, Interest Bearing) + // Custom parsers look for specific type-length-value (TLV) data at the end of the 165-byte base mint layout + console.log("Token-2022 mint detected. Reviewing transfer fee config..."); + } + + return { + program: ownerProgram, + isToken2022, + extensions, + }; +} +``` + +--- + +## 6. Durable Nonces + +Durable nonces allow transactions to bypass the standard 150-blockhash expiry window. This is critical for offline signers, high-security cold storage, or slow multi-agent pipeline resolution. + +```typescript +import { createSolanaRpc, Address } from "@solana/kit"; + +/** + * Checks the current nonce value of a durable nonce account + */ +export async function getNonceAccountValue( + rpcUrl: string, + nonceAccountAddress: Address +): Promise { + const rpc = createSolanaRpc(rpcUrl); + const accountInfo = await rpc.getAccountInfo(nonceAccountAddress).send(); + + if (!accountInfo || !accountInfo.value) { + throw new Error("Nonce account not found"); + } + + const data = accountInfo.value.data; + // Parse the NonceAccount state from data buffer: + // Nonce state starts with a 4-byte version, followed by 4-byte state, then public key (32 bytes) and blockhash (32 bytes) + const nonceBlockhash = Buffer.from(data).slice(40, 72).toString("hex"); + return nonceBlockhash; +} +``` + +--- + +## 7. Compute Budget & Priority Fees + +Enforcing custom compute budgets prevents transactions from failing due to out-of-gas errors or getting stuck in the mempool during network congestion. + +```typescript +import { addTransactionInstruction } from "@solana/kit"; +import { Buffer } from "buffer"; + +// Helper function to build ComputeBudget Program setComputeUnitPrice instruction +export function createSetComputeUnitPriceInstruction(microLamports: bigint) { + const data = Buffer.alloc(9); + data.writeUInt8(3, 0); // Discriminator + data.writeBigUInt64LE(microLamports, 1); // Micro-lamports + + return { + programId: "ComputeBudget111111111111111111111111111111" as Address, + keys: [], + data: new Uint8Array(data), + }; +} +``` diff --git a/skill/references/x402-testing.md b/skill/references/x402-testing.md new file mode 100644 index 0000000..db08d66 --- /dev/null +++ b/skill/references/x402-testing.md @@ -0,0 +1,256 @@ +# Testing & Mocking x402 Integrations + +Use this reference to configure unit tests, integration tests, CI pipelines, security test matrices, and load testing scripts for x402-enabled buyer agents and seller APIs. + +--- + +## 1. Vitest Configuration + +Configure Vitest with appropriate TypeScript and environment settings in `vitest.config.ts`. + +```typescript +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + globals: true, + environment: "node", + setupFiles: ["./tests/setup.ts"], + coverage: { + provider: "v8", + reporter: ["text", "json", "html"], + }, + testTimeout: 30000, // 30s timeout for blockchain interactions + }, +}); +``` + +--- + +## 2. GitHub Actions CI/CD Configuration + +Add a workflow in `.github/workflows/x402-tests.yml` to automatically verify routing and safety checks. + +```yaml +name: x402 Test Suite + +on: + push: + branches: [ main, dev ] + pull_request: + branches: [ main ] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install Dependencies + run: npm ci + + - name: Run Linter + run: npm run lint + + - name: Run Vitest Security Matrix + env: + SOLANA_RPC_URL: "https://api.devnet.solana.com" + SVM_PRIVATE_KEY: "3333333333333333333333333333333333333333333333333333333333333333" # Dev dummy key + X402_NETWORK: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" + run: npx vitest run +``` + +--- + +## 3. The 8-Case Security Test Matrix + +This matrix covers all security and integration edge cases that both the seller API and buyer client must validate. + +```typescript +import { describe, expect, it, vi, beforeEach } from "vitest"; +import request from "supertest"; +import { app } from "../src/app"; + +describe("x402 Security Matrix", () => { + // Guard against accidental mainnet testing + beforeEach(() => { + if (process.env.X402_NETWORK?.includes("5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp")) { + throw new Error("Refusing to run integration tests on Solana mainnet"); + } + }); + + // Case 1: Missing payment header returns 402 challenge + it("Case 1: returns HTTP 402 when no payment is supplied", async () => { + const res = await request(app).get("/api/v1/premium-data"); + expect(res.status).toBe(402); + expect(res.headers["www-authenticate"]).toContain("x402"); + }); + + // Case 2: Mutating paid route rejects if Idempotency-Key is missing + it("Case 2: rejects mutating routes when Idempotency-Key is missing", async () => { + const res = await request(app) + .post("/api/v1/generate") + .send({ prompt: "AI Art" }); + expect([400, 428]).toContain(res.status); // 400 Bad Request or 428 Precondition Required + }); + + // Case 3: Reject payments that specify an incorrect network + it("Case 3: rejects payments that specify an incorrect network", async () => { + const res = await request(app) + .get("/api/v1/premium-data") + .set("x-payment-txid", "mock-txid") + .set("x-payment-network", "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"); // Mainnet instead of Devnet + expect(res.status).toBe(400); + }); + + // Case 4: Reject payments that pay to an unexpected recipient + it("Case 4: rejects payments paying to an unexpected recipient", async () => { + const res = await request(app) + .get("/api/v1/premium-data") + .set("x-payment-txid", "txid-to-wrong-payee"); + // Verification engine checks tx details and rejects if payee is different + expect(res.status).toBe(403); + }); + + // Case 5: Reject payments that use an incorrect token mint + it("Case 5: rejects payments using an incorrect token mint", async () => { + const res = await request(app) + .get("/api/v1/premium-data") + .set("x-payment-txid", "txid-using-fake-usdc"); + expect(res.status).toBe(403); + }); + + // Case 6: Reject expired quotes/challenges + it("Case 6: rejects expired quotes", async () => { + const expiredTimestamp = Math.floor(Date.now() / 1000) - 120; // 2 minutes ago + const res = await request(app) + .get("/api/v1/premium-data") + .set("x-payment-quote-timestamp", expiredTimestamp.toString()) + .set("x-payment-txid", "mock-txid"); + expect(res.status).toBe(403); + }); + + // Case 7: Reject double-spending of the same transaction ID + it("Case 7: rejects double-spending (replay protection)", async () => { + // Submit first transaction + const res1 = await request(app) + .post("/api/v1/generate") + .set("Idempotency-Key", "key-1") + .set("x-payment-txid", "spent-txid-123"); + + // Submit second transaction with same txid + const res2 = await request(app) + .post("/api/v1/generate") + .set("Idempotency-Key", "key-2") + .set("x-payment-txid", "spent-txid-123"); + + expect(res2.status).toBe(409); // Conflict or 403 Forbidden + }); + + // Case 8: Enforce client spend policies + it("Case 8: client spend policy blocks requests exceeding budget caps", () => { + const maxBudget = 100000n; // 0.1 USDC + const requested = 200000n; // 0.2 USDC + + const assertSpend = () => { + if (requested > maxBudget) { + throw new Error("Blocked: per-request budget cap exceeded"); + } + }; + + expect(assertSpend).toThrow("Blocked: per-request budget cap exceeded"); + }); +}); +``` + +--- + +## 4. Load Testing with k6 + +Use `k6` to test the performance of the x402 payment resolution flow under high concurrency. Save this as `load-test.js`. + +```javascript +import http from 'k6/http'; +import { check, sleep } from 'k6'; + +export const options = { + stages: [ + { duration: '30s', target: 50 }, // Ramp-up to 50 users + { duration: '1m', target: 50 }, // Stay at 50 users + { duration: '30s', target: 0 }, // Ramp-down to 0 + ], +}; + +export default function () { + const url = 'http://localhost:3000/api/v1/premium-data'; + + // 1. Initial GET request (expects 402 challenge) + const res1 = http.get(url); + check(res1, { + 'status is 402': (r) => r.status === 402, + 'authenticate header present': (r) => r.headers['Www-Authenticate'] !== undefined, + }); + + // Extract payment details from Www-Authenticate header + const authHeader = res1.headers['Www-Authenticate'] || ''; + + // Simulate client building the transaction & paying... + // In a load test, mock the client signature latency (approx 50ms) + sleep(0.05); + + // 2. Submit payment (mocked txid for testing endpoint validation speeds) + const params = { + headers: { + 'x-payment-txid': `mock-txid-${__VU}-${__ITER}`, + 'Idempotency-Key': `idempotency-${__VU}-${__ITER}`, + }, + }; + + const res2 = http.get(url, params); + check(res2, { + 'status is 200': (r) => r.status === 200, + 'payment-response header returned': (r) => r.headers['Payment-Response'] !== undefined, + }); + + sleep(1); +} +``` + +--- + +## 5. Devnet Faucet Helper Script + +Use this script (`scripts/devnet-faucet.ts`) to automate funding of test wallets and minting of Devnet USDC. + +```typescript +import { createSolanaRpc, createKeyPairSignerFromBytes, Address } from "@solana/kit"; +import { base58 } from "@scure/base"; + +const DEVNET_RPC = "https://api.devnet.solana.com"; +const DEVNET_USDC_MINT = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"; + +export async function bootstrapDevnetWallet(privateKeyB58: string) { + const rpc = createSolanaRpc(DEVNET_RPC); + const signer = await createKeyPairSignerFromBytes(base58.decode(privateKeyB58)); + + console.log(`Bootstrapping wallet: ${signer.address}`); + + // 1. Request SOL Airdrop for fees + try { + const airdropSignature = await rpc.requestAirdrop(signer.address, 2_000_000_000n).send(); // 2 SOL + console.log(`SOL Airdrop request sent. Signature: ${airdropSignature}`); + } catch (error) { + console.warn("Airdrop limit reached or failed, proceeding with existing SOL balance..."); + } + + console.log(`Wallet bootstrap completed. Ready for Devnet testing.`); +} +```