diff --git a/examples/typescript/servers/spraay-gateway/.env-local b/examples/typescript/servers/spraay-gateway/.env-local new file mode 100644 index 0000000000..5f04182ff8 --- /dev/null +++ b/examples/typescript/servers/spraay-gateway/.env-local @@ -0,0 +1,17 @@ +# Your Ethereum address to receive x402 payments +PAY_TO_ADDRESS=0xYourAddressHere + +# x402 facilitator URL (default: x402.org testnet facilitator) +# For mainnet, use: https://api.cdp.coinbase.com/platform/v2/x402 +FACILITATOR_URL=https://x402.org/facilitator + +# Spraay gateway URL (production) +SPRAAY_GATEWAY_URL=https://gateway.spraay.app + +# Network (CAIP-2 format) +# Testnet: eip155:84532 (Base Sepolia) +# Mainnet: eip155:8453 (Base) +NETWORK=eip155:84532 + +# Server port +PORT=4021 diff --git a/examples/typescript/servers/spraay-gateway/README.md b/examples/typescript/servers/spraay-gateway/README.md new file mode 100644 index 0000000000..c916a9ca41 --- /dev/null +++ b/examples/typescript/servers/spraay-gateway/README.md @@ -0,0 +1,158 @@ +# Spraay Gateway – x402 Server Example + +An Express.js server that exposes [Spraay's](https://spraay.app) multi-chain payment infrastructure as x402-protected endpoints. AI agents pay per-request in USDC to access batch payments, payroll, token transfers, AI inference, and robot hiring (RTP) — across 13 blockchains. + +This example demonstrates how to put a **real production API with 76+ DeFi primitives** behind x402, so any agent with a wallet can discover and use them without accounts, API keys, or subscriptions. + +## What is Spraay? + +Spraay is a multi-chain batch payment protocol and x402 gateway. It lets AI agents: + +- **Send tokens to hundreds of recipients** in a single transaction (batch payments) +- **Run crypto payroll** for teams with one API call +- **Hire robots** to perform physical tasks via the Robot Task Protocol (RTP) +- **Access AI inference** across 43+ models (BlockRun multi-provider) +- **Swap, bridge, stake, and manage agent wallets** across Base, Ethereum, Solana, Bitcoin, and 9 other chains + +Live gateway: [gateway.spraay.app](https://gateway.spraay.app) +Docs: [docs.spraay.app](https://docs.spraay.app) +MCP Server: [@plagtech/spraay-x402-mcp](https://smithery.ai/server/@plagtech/spraay-x402-mcp) (60+ tools on Smithery) + +## Prerequisites + +- Node.js 18+ +- An Ethereum address to receive payments + +Optional (for mainnet): +- [Coinbase Developer Platform](https://portal.cdp.coinbase.com/projects) API Key & Secret + +## Setup + +Copy `.env-local` to `.env` and add your Ethereum address: + +```bash +cp .env-local .env +``` + +Install and build all packages from the typescript examples root: + +```bash +cd ../../ +pnpm install +pnpm build +cd servers/spraay-gateway +``` + +Run the server: + +```bash +pnpm dev +``` + +## Endpoints + +| Method | Path | Price | Description | +|--------|------|-------|-------------| +| `POST` | `/batch-payment` | $0.01 | Send USDC to multiple recipients in one tx | +| `POST` | `/token-transfer` | $0.01 | Transfer any ERC-20 token | +| `POST` | `/payroll` | $0.05 | Process recurring crypto payroll | +| `POST` | `/ai/inference` | $0.03 | Run AI inference (43+ models) | +| `POST` | `/rtp/task` | $0.05 | Hire a robot via Robot Task Protocol | +| `GET` | `/discover` | Free | List all gateway endpoints and pricing | + +These are a representative subset — the full Spraay gateway has **76+ paid endpoints across 16 categories**. + +## Testing + +You can test the server using any of the example x402 clients: + +```bash +cd ../../clients/fetch +# Ensure .env is set up with your private key +pnpm dev +``` + +Or use `curl` to see the 402 response: + +```bash +curl -i http://localhost:4021/batch-payment \ + -X POST \ + -H "Content-Type: application/json" \ + -d '{"chain":"base","recipients":["0x123..."],"amounts":["1.0"],"token":"USDC"}' +``` + +You'll receive a `402 Payment Required` response with payment details in the `PAYMENT-REQUIRED` header. + +## Example: Agent Batch Payment + +An AI agent paying to send USDC to 3 recipients: + +```typescript +import { withPaymentInterceptor } from "@x402/axios"; +import axios from "axios"; + +// Agent's wallet client (see x402 client examples) +const api = withPaymentInterceptor( + axios.create({ baseURL: "http://localhost:4021" }), + walletClient +); + +// Agent pays $0.01 USDC via x402, then Spraay executes +// a batch send to 3 recipients on Base +const result = await api.post("/batch-payment", { + chain: "base", + token: "USDC", + recipients: [ + "0xAlice...", + "0xBob...", + "0xCharlie...", + ], + amounts: ["10.00", "25.00", "15.00"], +}); + +console.log(result.data); +// { txHash: "0x...", recipients: 3, totalAmount: "50.00" } +``` + +## Running on Mainnet + +Update your `.env` to use Base mainnet and the CDP facilitator: + +```env +NETWORK=eip155:8453 +FACILITATOR_URL=https://api.cdp.coinbase.com/platform/v2/x402 +``` + +See the [CDP facilitator docs](https://docs.cdp.coinbase.com/x402/quickstart-for-sellers) for authentication setup. + +## Architecture + +``` +Agent (x402 client) + │ + │ 1. POST /batch-payment + │ 2. Receives 402 + payment requirements + │ 3. Signs USDC authorization + │ 4. Retries with X-PAYMENT header + │ + ▼ +x402 Express Middleware + │ + │ Verifies payment via facilitator + │ + ▼ +Spraay Gateway (gateway.spraay.app) + │ + │ Executes multi-chain DeFi operation + │ + ▼ +Base / Ethereum / Solana / Bitcoin / ... +``` + +## Links + +- [Spraay Gateway](https://gateway.spraay.app) — Live API +- [Spraay Docs](https://docs.spraay.app) — Full endpoint reference +- [MCP Server](https://smithery.ai/server/@plagtech/spraay-x402-mcp) — 60+ tools for Claude/AI agents +- [Bazaar Listing](https://x402.org) — x402 ecosystem +- [GitHub](https://github.com/plagtech) — All Spraay repos diff --git a/examples/typescript/servers/spraay-gateway/package.json b/examples/typescript/servers/spraay-gateway/package.json new file mode 100644 index 0000000000..515450e819 --- /dev/null +++ b/examples/typescript/servers/spraay-gateway/package.json @@ -0,0 +1,24 @@ +{ + "name": "x402-spraay-gateway-example", + "version": "1.0.0", + "private": true, + "description": "x402-protected gateway to Spraay's multi-chain batch payment, payroll, AI inference, and Robot Task Protocol (RTP) endpoints", + "scripts": { + "dev": "tsx src/index.ts", + "build": "tsc", + "start": "node dist/index.js" + }, + "dependencies": { + "@x402/core": "workspace:*", + "@x402/evm": "workspace:*", + "@x402/express": "workspace:*", + "dotenv": "^16.4.7", + "express": "^4.21.2" + }, + "devDependencies": { + "@types/express": "^5.0.1", + "@types/node": "^22.14.0", + "tsx": "^4.19.3", + "typescript": "^5.7.3" + } +} diff --git a/examples/typescript/servers/spraay-gateway/src/index.ts b/examples/typescript/servers/spraay-gateway/src/index.ts new file mode 100644 index 0000000000..14e60c5ae6 --- /dev/null +++ b/examples/typescript/servers/spraay-gateway/src/index.ts @@ -0,0 +1,252 @@ +import "dotenv/config"; +import express from "express"; +import { paymentMiddleware } from "@x402/express"; +import { ExactEvmScheme } from "@x402/evm/exact/server"; +import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server"; + +const app = express(); +app.use(express.json()); + +const { + PAY_TO_ADDRESS, + FACILITATOR_URL = "https://x402.org/facilitator", + SPRAAY_GATEWAY_URL = "https://gateway.spraay.app", + PORT = "4021", + NETWORK = "eip155:84532", +} = process.env; + +if (!PAY_TO_ADDRESS) { + console.error("PAY_TO_ADDRESS is required in .env"); + process.exit(1); +} + +// --------------------------------------------------------- +// Route pricing – mirrors Spraay's live gateway categories +// --------------------------------------------------------- +// Spraay exposes 76+ paid endpoints across 16 categories and +// 13 chains (Base, Ethereum, Arbitrum, Polygon, BNB, Avalanche, +// Unichain, Plasma, BOB, Solana, Bittensor, Stacks, Bitcoin). +// +// This example demonstrates a representative subset so agents +// can discover and pay for DeFi primitives, payroll, robot +// hiring (RTP), and AI inference — all via x402. +// --------------------------------------------------------- + +const routePricing: Record = { + // Category 1 – Batch Payments (core primitive) + "POST /batch-payment": { + accepts: { + scheme: "exact", + price: "$0.01", + network: NETWORK, + payTo: PAY_TO_ADDRESS, + }, + description: + "Send USDC to multiple recipients in a single transaction on any supported chain", + mimeType: "application/json", + }, + + // Category 4 – Token Transfers + "POST /token-transfer": { + accepts: { + scheme: "exact", + price: "$0.01", + network: NETWORK, + payTo: PAY_TO_ADDRESS, + }, + description: "Transfer any ERC-20 token between addresses", + mimeType: "application/json", + }, + + // Category 6 – Payroll + "POST /payroll": { + accepts: { + scheme: "exact", + price: "$0.05", + network: NETWORK, + payTo: PAY_TO_ADDRESS, + }, + description: + "Process recurring payroll for multiple employees in one transaction", + mimeType: "application/json", + }, + + // Category 13 – AI Inference + "POST /ai/inference": { + accepts: { + scheme: "exact", + price: "$0.03", + network: NETWORK, + payTo: PAY_TO_ADDRESS, + }, + description: + "Run AI inference via Spraay's BlockRun multi-provider gateway (43+ models)", + mimeType: "application/json", + }, + + // Category 15 – Robot Task Protocol (RTP) + "POST /rtp/task": { + accepts: { + scheme: "exact", + price: "$0.05", + network: NETWORK, + payTo: PAY_TO_ADDRESS, + }, + description: + "Hire a robot to perform a physical task via RTP (Robot Task Protocol)", + mimeType: "application/json", + }, + + // Discovery – free endpoint (no payment required) + "GET /discover": { + accepts: { + scheme: "exact", + price: "$0.00", + network: NETWORK, + payTo: PAY_TO_ADDRESS, + }, + description: "List all available Spraay gateway endpoints and pricing", + mimeType: "application/json", + }, +}; + +// --------------------------------------------------------- +// x402 middleware – one line to protect all routes +// --------------------------------------------------------- +const facilitatorClient = new HTTPFacilitatorClient({ url: FACILITATOR_URL }); +const resourceServer = new x402ResourceServer(facilitatorClient).register( + NETWORK, + new ExactEvmScheme(), +); + +app.use(paymentMiddleware(routePricing, resourceServer)); + +// --------------------------------------------------------- +// Route handlers – proxy to the live Spraay gateway +// --------------------------------------------------------- + +// Helper to forward requests to Spraay +async function proxyToSpraay(path: string, body?: object) { + const res = await fetch(`${SPRAAY_GATEWAY_URL}${path}`, { + method: body ? "POST" : "GET", + headers: { "Content-Type": "application/json" }, + ...(body && { body: JSON.stringify(body) }), + }); + return res.json(); +} + +// Batch payment – send to multiple recipients +app.post("/batch-payment", async (req, res) => { + try { + const result = await proxyToSpraay("/batch-payment", req.body); + res.json(result); + } catch (error) { + res.status(500).json({ error: "Failed to process batch payment" }); + } +}); + +// Token transfer +app.post("/token-transfer", async (req, res) => { + try { + const result = await proxyToSpraay("/token-transfer", req.body); + res.json(result); + } catch (error) { + res.status(500).json({ error: "Failed to process token transfer" }); + } +}); + +// Payroll +app.post("/payroll", async (req, res) => { + try { + const result = await proxyToSpraay("/payroll", req.body); + res.json(result); + } catch (error) { + res.status(500).json({ error: "Failed to process payroll" }); + } +}); + +// AI Inference +app.post("/ai/inference", async (req, res) => { + try { + const result = await proxyToSpraay("/ai/inference", req.body); + res.json(result); + } catch (error) { + res.status(500).json({ error: "Failed to run AI inference" }); + } +}); + +// RTP – Robot Task Protocol +app.post("/rtp/task", async (req, res) => { + try { + const result = await proxyToSpraay("/rtp/task", req.body); + res.json(result); + } catch (error) { + res.status(500).json({ error: "Failed to submit robot task" }); + } +}); + +// Discovery – list all endpoints +app.get("/discover", (_req, res) => { + res.json({ + name: "Spraay x402 Gateway", + description: + "Multi-chain batch payment protocol + AI inference + Robot Task Protocol (RTP). 76+ endpoints across 13 chains.", + version: "3.5.0", + docs: "https://docs.spraay.app", + mcp_server: "npm: @plagtech/spraay-x402-mcp", + categories: [ + { id: 1, name: "Batch Payments", endpoints: 8, price: "$0.01" }, + { id: 2, name: "Token Swaps", endpoints: 6, price: "$0.01" }, + { id: 3, name: "Bridge", endpoints: 4, price: "$0.05" }, + { id: 4, name: "Token Transfers", endpoints: 6, price: "$0.01" }, + { id: 5, name: "NFT Operations", endpoints: 5, price: "$0.01" }, + { id: 6, name: "Payroll", endpoints: 4, price: "$0.05" }, + { id: 7, name: "Escrow", endpoints: 4, price: "$0.05" }, + { id: 8, name: "Governance", endpoints: 4, price: "$0.01" }, + { id: 9, name: "Oracle", endpoints: 4, price: "$0.005" }, + { id: 10, name: "DeFi Analytics", endpoints: 5, price: "$0.01" }, + { id: 11, name: "Gas Optimization", endpoints: 3, price: "$0.005" }, + { id: 12, name: "ENS", endpoints: 3, price: "$0.01" }, + { id: 13, name: "AI Inference", endpoints: 6, price: "$0.03" }, + { id: 14, name: "Agent Utilities", endpoints: 5, price: "$0.01" }, + { id: 15, name: "Robot Task Protocol", endpoints: 8, price: "$0.05" }, + { id: 16, name: "Staking", endpoints: 4, price: "$0.01" }, + { id: 17, name: "Agent Wallets", endpoints: 7, price: "$0.01" }, + ], + chains: [ + "Base", + "Ethereum", + "Arbitrum", + "Polygon", + "BNB Chain", + "Avalanche", + "Unichain", + "Plasma", + "BOB", + "Solana", + "Bittensor", + "Stacks", + "Bitcoin", + ], + payment_address: "0xAd62f03C7514bb8c51f1eA70C2b75C37404695c8", + }); +}); + +// --------------------------------------------------------- +// Start +// --------------------------------------------------------- +app.listen(Number(PORT), () => { + console.log(`\n💧 Spraay x402 Gateway Example`); + console.log(` Server: http://localhost:${PORT}`); + console.log(` Pay to: ${PAY_TO_ADDRESS}`); + console.log(` Network: ${NETWORK}`); + console.log(` Facilitator: ${FACILITATOR_URL}`); + console.log(` Spraay API: ${SPRAAY_GATEWAY_URL}\n`); + console.log(` Endpoints:`); + console.log(` POST /batch-payment $0.01 – Multi-recipient USDC sends`); + console.log(` POST /token-transfer $0.01 – ERC-20 transfers`); + console.log(` POST /payroll $0.05 – Recurring crypto payroll`); + console.log(` POST /ai/inference $0.03 – AI model inference`); + console.log(` POST /rtp/task $0.05 – Hire a robot (RTP)`); + console.log(` GET /discover free – Endpoint discovery\n`); +}); diff --git a/examples/typescript/servers/spraay-gateway/tsconfig.json b/examples/typescript/servers/spraay-gateway/tsconfig.json new file mode 100644 index 0000000000..123f63ce22 --- /dev/null +++ b/examples/typescript/servers/spraay-gateway/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +}