diff --git a/README.md b/README.md index 3172e26..7d70774 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,28 @@ -# Cashu Redeem API ๐Ÿช™โšก +# Cashu Redeem API -API for redeeming Cashu tokens (ecash) to Lightning addresses using the cashu-ts library and LNURLp protocol. +A production-grade API for redeeming Cashu tokens (ecash) to Lightning addresses using the [cashu-ts](https://github.com/cashubtc/cashu-ts) library and LNURLp protocol. -## ๐Ÿš€ Features +## Features -- **Decode Cashu tokens** - Parse and validate token content -- **Redeem to Lightning addresses** - Convert ecash to Lightning payments via LNURLp -- **Security features** - Domain restrictions, rate limiting, input validation -- **Robust error handling** - Comprehensive error messages -- **Interactive API Documentation** - Complete Swagger/OpenAPI documentation at `/docs` +- **Decode Cashu tokens** - Parse and validate token content, check spendability at the mint +- **Redeem to Lightning addresses** - Convert ecash to Lightning payments via LNURLp with exact fee calculation +- **Lightning address validation** - Verify addresses and query LNURLp capabilities +- **Duplicate detection** - In-memory tracking prevents double-spend attempts +- **Security** - Domain restrictions, rate limiting, input validation, CORS protection +- **Interactive API docs** - Complete Swagger/OpenAPI documentation at `/docs` +## API Documentation -## ๐Ÿ“– API Documentation +Interactive Swagger documentation is available at `/docs` when the server is running. -**Interactive Swagger Documentation**: Visit `/docs` when running the server for a complete, interactive API reference. +- Local: `http://localhost:3000/docs` +- OpenAPI spec: `http://localhost:3000/openapi.json` -Example: `https://cashu-redeem.azzamo.net/docs/` +## API Endpoints -## ๐Ÿ“ก API Endpoints +### `POST /api/decode` -### 1. `POST /api/decode` -Decode a Cashu token and return its content. Supports both v1 and v3 token formats. +Decode a Cashu token and return its content. Supports both v3 (`cashuB`) and v1 (`cashuA`) token formats. Checks spendability against the mint. **Request:** ```json @@ -34,25 +36,33 @@ Decode a Cashu token and return its content. Supports both v1 and v3 token forma { "success": true, "decoded": { - "mint": "https://mint.azzamo.net", - "totalAmount": 21000, - "numProofs": 3, - "denominations": [1000, 10000, 10000], - "format": "cashuA", + "mint": "https://kashu.me", + "totalAmount": 16, + "numProofs": 5, + "denominations": [8, 4, 2, 1, 1], + "format": "cashuB", "spent": false }, - "mint_url": "https://mint.azzamo.net" + "mint_url": "https://kashu.me" } ``` -### 2. `POST /api/redeem` -Redeem a Cashu token to a Lightning address. Lightning address is optional - if not provided, uses the default address from configuration. +### `POST /api/redeem` + +Redeem a Cashu token to a Lightning address. The Lightning address is optional if a default is configured. + +The redemption process: +1. Token validation and parsing +2. Spendability check at the mint +3. Melt quote to determine exact fees +4. Invoice creation for the net amount (token amount minus fees) +5. Token melting and Lightning payment **Request:** ```json { "token": "cashuB...", - "lightningAddress": "user@ln.tips" + "lightningAddress": "user@twentyone.tips" } ``` @@ -68,50 +78,36 @@ Redeem a Cashu token to a Lightning address. Lightning address is optional - if { "success": true, "paid": true, - "amount": 21000, - "invoiceAmount": 20580, - "to": "user@ln.tips", - "fee": 1000, - "actualFee": 420, - "netAmount": 20000, - "mint_url": "https://mint.azzamo.net", - "format": "cashuA", - "preimage": "abc123..." + "amount": 16, + "invoiceAmount": 14, + "to": "user@twentyone.tips", + "fee": 2, + "netAmount": 14, + "mint_url": "https://kashu.me", + "format": "cashuB", + "preimage": "d5af74a3..." } ``` -**Success Response (using default address):** -```json -{ - "success": true, - "paid": true, - "amount": 21000, - "invoiceAmount": 20580, - "to": "admin@your-domain.com", - "fee": 1000, - "actualFee": 420, - "netAmount": 20000, - "mint_url": "https://mint.azzamo.net", - "format": "cashuA", - "usingDefaultAddress": true, - "message": "Redeemed to default Lightning address: admin@your-domain.com" -} -``` +**Response fields:** +| Field | Description | +|-------|-------------| +| `amount` | Total token amount in sats | +| `invoiceAmount` | Amount sent to the Lightning address (after fees) | +| `fee` | Exact fee charged by the mint (from melt quote) | +| `netAmount` | Net amount received | +| `preimage` | Lightning payment preimage (proof of payment) | +| `usingDefaultAddress` | Present and `true` when the default address was used | -**Payment Verification**: -The API uses multiple indicators to verify payment success: -- `paid` flag from mint response -- Presence of payment preimage -- Payment state indicators +### `POST /api/validate-address` -### 3. `POST /api/validate-address` -Validate a Lightning address without redemption. +Validate a Lightning address without performing a redemption. Tests LNURLp resolution and returns address capabilities. **Request:** ```json { - "lightningAddress": "user@ln.tips" + "lightningAddress": "user@twentyone.tips" } ``` @@ -120,48 +116,54 @@ Validate a Lightning address without redemption. { "success": true, "valid": true, - "domain": "ln.tips", + "domain": "twentyone.tips", "minSendable": 1, - "maxSendable": 100000000, - "commentAllowed": 144 + "maxSendable": 1000000, + "commentAllowed": 2000 } ``` -### 4. `GET /api/health` -Health check endpoint. +### `GET /api/health` + +Health check endpoint returning server status, uptime, and memory usage. **Response:** ```json { "status": "ok", - "timestamp": "2025-01-14T12:00:00Z", - "uptime": 3600, - "memory": {...}, - "version": "1.0.0" + "timestamp": "2026-02-17T03:36:40.987Z", + "uptime": 170.23, + "memory": { "rss": 83873792, "heapTotal": 20520960, "heapUsed": 17170824 }, + "version": "2.0.0" } ``` -## ๐Ÿ›  Setup & Installation +### `GET /openapi.json` + +Returns the full OpenAPI 3.0 specification as JSON. + +## Setup & Installation ### Prerequisites + - Node.js >= 18.0.0 -- npm or yarn +- npm >= 8.0.0 ### Installation 1. **Clone and install dependencies:** ```bash -git clone +git clone https://github.com/Michilis/cashu-redeem-api.git cd cashu-redeem-api npm install ``` -2. **Setup environment variables:** +2. **Configure environment variables:** ```bash cp env.example .env ``` -Edit `.env` file: +Edit `.env`: ```bash # Server Configuration PORT=3000 @@ -171,108 +173,148 @@ NODE_ENV=development API_DOMAIN=localhost:3000 # Security Configuration -ALLOW_REDEEM_DOMAINS=ln.tips,getalby.com,wallet.mutinywallet.com -API_SECRET=your-secret-key-here +ALLOW_REDEEM_DOMAINS=* # Default Lightning Address (used when no address is provided in redeem requests) DEFAULT_LIGHTNING_ADDRESS=admin@your-domain.com -# Rate Limiting (requests per minute) -RATE_LIMIT=100 +# Rate Limiting (requests per minute per IP) +RATE_LIMIT=30 + +# Logging +LOG_LEVEL=info # CORS Configuration -ALLOWED_ORIGINS=http://localhost:3000,https://yourdomain.com +ALLOWED_ORIGINS=* ``` 3. **Start the server:** ```bash -# Development +# Development (with auto-reload) npm run dev # Production npm start ``` - -## ๐Ÿ”ง Configuration +## Configuration ### Environment Variables | Variable | Description | Default | Required | |----------|-------------|---------|----------| | `PORT` | Server port | `3000` | No | -| `NODE_ENV` | Environment | `development` | No | -| `ALLOW_REDEEM_DOMAINS` | Comma-separated allowed domains | All allowed | No | +| `NODE_ENV` | Environment (`development` / `production`) | `development` | No | +| `API_DOMAIN` | Domain for Swagger docs and CORS | `localhost:3000` | No | +| `ALLOW_REDEEM_DOMAINS` | Comma-separated allowed Lightning address domains (`*` for all) | All allowed | No | | `DEFAULT_LIGHTNING_ADDRESS` | Default Lightning address for redemptions | None | No | | `RATE_LIMIT` | Requests per minute per IP | `100` | No | -| `ALLOWED_ORIGINS` | CORS allowed origins | `http://localhost:3000` | No | +| `LOG_LEVEL` | Logging level | `info` | No | +| `ALLOWED_ORIGINS` | CORS allowed origins (`*` for all) | `http://localhost:3000` | No | ### Domain Restrictions -To restrict redemptions to specific Lightning address domains, set: +Restrict redemptions to specific Lightning address domains: ```bash -ALLOW_REDEEM_DOMAINS=ln.tips,getalby.com,wallet.mutinywallet.com +ALLOW_REDEEM_DOMAINS=twentyone.tips,getalby.com,walletofsatoshi.com ``` -If not set, all domains are allowed. +If set to `*` or not set, all domains are allowed. ### Default Lightning Address -To set a default Lightning address that will be used when no address is provided in redemption requests: +Set a fallback address used when no address is provided in redemption requests: ```bash DEFAULT_LIGHTNING_ADDRESS=admin@your-domain.com ``` -This allows users to redeem tokens without specifying a Lightning address - the tokens will automatically be sent to your configured default address. If no default is set, Lightning address becomes required for all redemption requests. +If no default is configured, the `lightningAddress` field becomes required for all redemption requests. +## Project Structure -### Data Flow +``` +cashu-redeem-api/ + server.js # Express app, middleware, route mounting + swagger.config.js # OpenAPI/Swagger configuration and schemas + components/ + cashu.js # Token parsing, spendability checks, melt operations + lightning.js # LNURLp resolution, invoice creation, address validation + redemption.js # Orchestrates the full redemption flow + routes/ + cashu.js # POST /api/decode + redemption.js # POST /api/redeem + lightning.js # POST /api/validate-address + health.js # GET /api/health +``` -1. **Token Validation** - Parse and validate Cashu token structure -2. **Address Resolution** - Resolve Lightning address to LNURLp endpoint -3. **Invoice Generation** - Create Lightning invoice for the amount -4. **Token Melting** - Use cashu-ts to melt token and pay invoice +## Redemption Flow -## ๐Ÿ”’ Security Features +1. **Token Parsing** - Validate and decode the Cashu token structure +2. **Spendability Check** - Verify proofs are unspent at the mint +3. **Melt Quote** - Get exact fee from the mint before creating the invoice +4. **Address Resolution** - Resolve Lightning address via LNURLp +5. **Invoice Generation** - Create a Lightning invoice for the net amount (total minus fee) +6. **Token Melting** - Melt the token at the mint to pay the invoice -- **Input validation** - All inputs are sanitized and validated -- **Rate limiting** - 100 requests per minute per IP (configurable) -- **Domain restrictions** - Limit allowed Lightning address domains -- **CORS protection** - Configurable allowed origins -- **Error handling** - Comprehensive error messages without data leaks - -## ๐Ÿšฆ Status Codes +## Internal Status Codes | Status | Description | |--------|-------------| -| `processing` | Redemption is in progress | +| `processing` | Redemption initiated | | `parsing_token` | Validating and parsing the token | -| `resolving_invoice` | Resolving Lightning address to invoice | +| `checking_spendability` | Checking proofs at the mint | +| `getting_melt_quote` | Requesting fee quote from mint | +| `resolving_invoice` | Creating Lightning invoice via LNURLp | | `melting_token` | Performing the melt operation | -| `paid` | Successfully paid and completed | +| `paid` | Successfully completed | | `failed` | Redemption failed (see error details) | +## Security Features -## ๐Ÿงช Testing +- **Input validation** - All inputs are sanitized and validated +- **Rate limiting** - Configurable per-IP request limits +- **Domain restrictions** - Limit allowed Lightning address domains +- **CORS protection** - Configurable allowed origins +- **Duplicate detection** - Prevents resubmission of already-redeemed tokens +- **Error handling** - Comprehensive error messages without sensitive data leaks -### Interactive Testing with Swagger +## Testing -The easiest way to test the API is using the interactive Swagger documentation at `/docs`: -- Visit `http://localhost:3000/docs` -- Click "Try it out" on any endpoint -- Fill in the request parameters -- Execute the request directly from the browser +The easiest way to test the API is using the interactive Swagger documentation: +1. Start the server: `npm run dev` +2. Visit `http://localhost:3000/docs` +3. Click "Try it out" on any endpoint +4. Fill in the request parameters and execute +Or use curl: +```bash +# Health check +curl http://localhost:3000/api/health -## ๐Ÿค Contributing +# Decode a token +curl -X POST http://localhost:3000/api/decode \ + -H "Content-Type: application/json" \ + -d '{"token": "cashuB..."}' + +# Validate a Lightning address +curl -X POST http://localhost:3000/api/validate-address \ + -H "Content-Type: application/json" \ + -d '{"lightningAddress": "user@twentyone.tips"}' + +# Redeem a token +curl -X POST http://localhost:3000/api/redeem \ + -H "Content-Type: application/json" \ + -d '{"token": "cashuB...", "lightningAddress": "user@twentyone.tips"}' +``` + +## Contributing 1. Fork the repository 2. Create a feature branch 3. Make your changes -4. Add tests if applicable -5. Submit a pull request +4. Submit a pull request -## ๐Ÿ“ License +## License MIT License - see LICENSE file for details.