ws402
Version:
WebSocket implementation of X402 protocol for pay-as-you-go digital resources with automatic refunds
606 lines (472 loc) ⢠15.3 kB
Markdown
# WS402
> WebSocket implementation of X402 protocol for pay-as-you-go digital resources with automatic refunds
[](https://www.npmjs.com/package/ws402)
[](https://opensource.org/licenses/MIT)
## Overview
WS402 extends the X402 protocol to WebSocket connections, enabling true pay-as-you-go pricing for streaming resources. Users pay upfront for estimated usage, the backend tracks actual consumption in real-time, and unused balance is automatically refunded when the session ends.
**Perfect for:**
- š„ Video/audio streaming
- š API access with metered billing
- š Real-time data feeds
- āļø Cloud computing resources
- š¤ AI model inference
- š® Gaming servers
- š VPN services
## Features
- ā
**Automatic refunds** - Users only pay for what they actually consume
- ā” **Real-time metering** - Track usage by time, bytes, or custom metrics
- š **Payment verification** - Built-in blockchain payment verification
- š **Multi-blockchain support** - Base, Solana, and custom providers
- š¦ **Centralized gateway** - Optional proxy architecture for enterprise
- š **Usage tracking** - Detailed session metrics and callbacks
- šÆ **Simple integration** - Similar to X402, easy to add to existing apps
- š **Payment provider agnostic** - Works with any payment system
## Installation
```bash
npm install ws402
```
**Additional dependencies for blockchain providers:**
```bash
# For Base blockchain
npm install ethers
# For Solana blockchain
npm install @solana/web3.js @solana/pay bignumber.js
```
## Quick Start
### Basic Server (Mock Provider)
```javascript
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const { WS402, MockPaymentProvider } = require('ws402');
const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
// Initialize payment provider (mock for development)
const paymentProvider = new MockPaymentProvider();
// Create WS402 instance
const ws402 = new WS402(
{
updateInterval: 3000, // Send updates every 3 seconds
pricePerSecond: 10, // Price per second in wei
currency: 'wei',
maxSessionDuration: 600, // Max 10 minutes per session
onPaymentVerified: (session) => {
console.log(`ā
Payment verified: ${session.sessionId}`);
},
onRefundIssued: (session, refund) => {
console.log(`š° Refund issued: ${refund.amount} wei`);
},
onSessionEnd: (session) => {
console.log(`š Session ended: ${session.sessionId}`);
},
},
paymentProvider
);
// Attach to WebSocket server
ws402.attach(wss);
// Serve WS402 schema
app.get('/ws402/schema/:resourceId', (req, res) => {
const schema = ws402.generateSchema(
req.params.resourceId,
300 // estimated duration in seconds
);
res.json(schema);
});
server.listen(4028);
```
### Client Integration
```javascript
// 1. Fetch WS402 schema
const response = await fetch('/ws402/schema/my-resource?duration=300');
const schema = await response.json();
// 2. Make payment (using blockchain or other method)
// ... payment process ...
// 3. Connect to WebSocket
const ws = new WebSocket(`wss://your-server.com?userId=alice`);
// 4. Send payment proof
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'payment_proof',
proof: {
txHash: '0x123...', // Blockchain transaction hash
reference: schema.paymentDetails.reference,
senderAddress: '0xYourAddress...',
amount: schema.pricing.totalPrice,
}
}));
};
// 5. Receive usage updates
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'session_started') {
console.log('ā
Session active!', data.sessionId);
}
if (data.type === 'usage_update') {
console.log(`ā±ļø Time: ${data.elapsedSeconds}s`);
console.log(`š° Remaining: ${data.remainingBalance} wei`);
}
if (data.type === 'balance_exhausted') {
console.log('ā ļø Balance exhausted');
}
};
// 6. Disconnect to trigger automatic refund
ws.close();
```
## Payment Providers
WS402 supports multiple payment architectures:
### 1. Base Blockchain (Direct Integration)
```javascript
const { WS402, BasePaymentProvider } = require('ws402');
const baseProvider = new BasePaymentProvider({
rpcEndpoint: 'https://mainnet.base.org',
merchantWallet: '0xYourWalletAddress',
merchantPrivateKey: process.env.MERCHANT_PRIVATE_KEY, // For automatic refunds
network: 'base', // 'base' | 'base-goerli' | 'base-sepolia'
autoRefund: true,
});
const ws402 = new WS402(config, baseProvider);
```
**Features:**
- ā
Native ETH payments on Base L2
- ā
ERC20 token support
- ā
~$0.01 transaction fees
- ā
2-5 second confirmations
- ā
Automatic on-chain refunds
### 2. Solana Blockchain (Direct Integration)
```javascript
const { WS402, SolanaPaymentProvider } = require('ws402');
const solanaProvider = new SolanaPaymentProvider({
rpcEndpoint: 'https://api.mainnet-beta.solana.com',
merchantWallet: 'YourSolanaPublicKey',
network: 'mainnet-beta',
conversionRate: 1000000000, // wei to lamports
label: 'WS402 Payment',
message: 'Pay for WebSocket access',
});
const ws402 = new WS402(config, solanaProvider);
```
**Features:**
- ā
Native SOL payments
- ā
SPL token support (USDC, USDT, etc.)
- ā
Solana Pay QR codes
- ā
~$0.0001 transaction fees
- ā
Sub-second confirmations
- ā
Automatic on-chain refunds
### 3. Proxy Architecture (Enterprise/Multi-Server)
Perfect for scaling and security:
```javascript
const { WS402, ProxyPaymentProvider } = require('ws402');
// WS402 Server (no private keys needed!)
const proxyProvider = new ProxyPaymentProvider({
gatewayUrl: 'https://payment-gateway.example.com',
apiKey: process.env.GATEWAY_API_KEY,
timeout: 30000,
retryAttempts: 3,
});
const ws402 = new WS402(config, proxyProvider);
```
**Architecture:**
```
[Client] ā [WS402 Server A] ā¤
[Client] ā [WS402 Server B] ā„ā [Payment Gateway] ā [Blockchain]
[Client] ā [WS402 Server C] ⦠(has private keys)
```
**Benefits:**
- š Private keys only on gateway (more secure)
- š Easy horizontal scaling
- š Multiple WS402 servers, one gateway
- š Centralized payment logging
- š ļø Easier compliance and auditing
**Gateway Server:**
```javascript
// Centralized gateway with private keys
node examples/payment-gateway-server.js
```
**See:** [PROXY_ARCHITECTURE.md](./PROXY_ARCHITECTURE.md) for details
### 4. Custom Payment Provider
Implement the `PaymentProvider` interface:
```typescript
interface PaymentProvider {
generatePaymentDetails(amount: number): any;
verifyPayment(proof: any): Promise<PaymentVerification>;
issueRefund(proof: any, amount: number): Promise<void>;
}
```
Example:
```javascript
class MyPaymentProvider {
async generatePaymentDetails(amount) {
return {
invoiceUrl: 'https://pay.me/invoice-123',
amount,
currency: 'USD',
};
}
async verifyPayment(proof) {
const isValid = await this.checkWithAPI(proof);
return {
valid: isValid,
amount: proof.amount,
};
}
async issueRefund(proof, amount) {
await this.refundAPI(proof, amount);
}
}
```
## Configuration Options
```typescript
interface WS402Config {
updateInterval?: number; // Update frequency (ms) - default: 3000
pricePerSecond?: number; // Price per second - default: 1
currency?: string; // Currency unit - default: 'wei'
maxSessionDuration?: number; // Max session time (seconds) - default: 3600
userIdExtractor?: (req) => string; // Extract user ID from request
onPaymentVerified?: (session) => void;
onRefundIssued?: (session, refund) => void;
onSessionEnd?: (session) => void;
}
```
## WS402 Schema
When a client requests a protected resource, return a WS402 schema:
```json
{
"protocol": "ws402",
"version": "0.1.0",
"resourceId": "video-123",
"websocketEndpoint": "wss://api.example.com/ws402/video-123",
"pricing": {
"pricePerSecond": 10,
"currency": "wei",
"estimatedDuration": 300,
"totalPrice": 3000
},
"paymentDetails": {
"type": "base",
"network": "base",
"chainId": 8453,
"recipient": "0x...",
"amountETH": "0.000003",
"reference": "base_123_abc"
},
"maxSessionDuration": 600
}
```
## Message Types
### Client ā Server
**Payment Proof**
```json
{
"type": "payment_proof",
"proof": {
"txHash": "0x123...",
"reference": "base_123_abc",
"senderAddress": "0xUser...",
"amount": 3000
}
}
```
### Server ā Client
**Session Started**
```json
{
"type": "session_started",
"sessionId": "ws402_123_abc",
"balance": 3000,
"pricePerSecond": 10
}
```
**Usage Update**
```json
{
"type": "usage_update",
"sessionId": "ws402_123_abc",
"elapsedSeconds": 45,
"consumedAmount": 450,
"remainingBalance": 2550,
"bytesTransferred": 1024000,
"messageCount": 15
}
```
**Balance Exhausted**
```json
{
"type": "balance_exhausted",
"message": "Prepaid balance has been fully consumed"
}
```
**Payment Rejected**
```json
{
"type": "payment_rejected",
"reason": "Invalid payment proof"
}
```
## Examples
See the `/examples` directory for complete working examples:
### Development
- `basic-server.js` - Mock payment provider for testing
- `base-server.js` - Base blockchain integration
- `solana-server.js` - Solana blockchain integration
- `proxy-server.js` - Proxy architecture with gateway
- `payment-gateway-server.js` - Centralized payment gateway
### Clients
- `base-client.html` - Web client with MetaMask integration
- `solana-client.html` - Web client with Solana Pay
- `proxy-client.html` - Web client for proxy architecture
### Run Examples
```bash
# Development with mock payments
npm run example
# Base blockchain
npm run example:base
# Solana blockchain
npm run example:solana
# Proxy architecture (run gateway first)
node examples/payment-gateway-server.js # Terminal 1
node examples/proxy-server.js # Terminal 2
```
Then open http://localhost:4028 in your browser.
## Session Lifecycle
```
1. Client requests resource ā Server returns WS402 schema
2. Client makes payment ā Blockchain transaction
3. Client connects via WebSocket ā Sends payment proof
4. Server verifies payment on-chain ā Starts session
5. Real-time metering ā Server sends periodic updates
6. Client disconnects ā Server calculates consumed amount
7. Automatic refund ā Unused balance returned on-chain
```
## Comparison
### WS402 vs X402
| Feature | X402 | WS402 |
|---------|------|-------|
| Protocol | HTTP | WebSocket |
| Payment timing | Pay-per-request | Pay upfront, refund unused |
| Connection | Stateless | Stateful |
| Real-time updates | No | Yes |
| Refunds | No | Automatic |
| Use case | API endpoints | Streaming resources |
### Payment Provider Comparison
| Provider | Fees | Speed | Best For |
|----------|------|-------|----------|
| **Base** | ~$0.01 | 2-5 sec | Ethereum users, DeFi apps |
| **Solana** | ~$0.0001 | <1 sec | High volume, low fees |
| **Proxy** | Provider dependent | Provider dependent | Enterprise, multi-server |
| **Mock** | Free | Instant | Development, testing |
## API Reference
### `WS402`
Main class for WS402 protocol implementation.
#### Constructor
```javascript
new WS402(config: WS402Config, paymentProvider: PaymentProvider)
```
#### Methods
- `attach(wss: WebSocket.Server)` - Attach to WebSocket server
- `generateSchema(resourceId, estimatedDuration)` - Generate WS402 schema
- `getSessionByUserId(userId)` - Get active session by user ID
- `getActiveSessions()` - Get all active sessions
#### Events
- `session_end` - Emitted when session ends
- `refund` - Emitted when refund is issued
- `refund_error` - Emitted when refund fails
- `error` - Emitted on errors
### Payment Providers
See detailed documentation:
- [Payment Providers Guide](./docs/PROVIDERS_README.md)
- [Proxy Architecture](./docs/PROXY_ARCHITECTURE.md)
- [Security Guide](./docs/SECURITY.md)
## Environment Variables
```bash
# Base Blockchain
BASE_RPC=https://mainnet.base.org
MERCHANT_WALLET=0xYourWalletAddress
MERCHANT_PRIVATE_KEY=your_private_key_here
# Solana Blockchain
SOLANA_RPC=https://api.mainnet-beta.solana.com
SOLANA_WALLET=YourSolanaPublicKey
# Proxy Gateway
GATEWAY_URL=https://payment-gateway.example.com
GATEWAY_API_KEY=your-secret-api-key
# Server
PORT=4028
```
See [`.env.example`](./.env.example) for full configuration.
## Security
### Private Key Management
ā ļø **CRITICAL**: Never expose private keys in code or repositories!
```javascript
// ā NEVER DO THIS
const provider = new BasePaymentProvider({
merchantPrivateKey: '0x123abc...'
});
// ā
ALWAYS USE ENVIRONMENT VARIABLES
const provider = new BasePaymentProvider({
merchantPrivateKey: process.env.MERCHANT_PRIVATE_KEY
});
```
**Best Practices:**
- Use environment variables
- Store keys in secure vaults (AWS Secrets Manager, HashiCorp Vault)
- Use different wallets for dev/test/prod
- Consider proxy architecture for production
- Enable automatic refunds only on secure servers
See [SECURITY.md](./docs/SECURITY.md) for complete security guide.
## Production Deployment
### Option 1: Direct Integration (Small Scale)
```
[WS402 Server] ā [Blockchain]
```
- Simple setup
- Good for single server
- Requires private key on server
### Option 2: Proxy Architecture (Enterprise)
```
[Load Balancer]
ā
[WS402 Servers] ā [Payment Gateway] ā [Blockchain]
(private keys here)
```
- Highly scalable
- Centralized security
- Multiple WS402 servers
- Recommended for production
See [PROXY_ARCHITECTURE.md](./docs/PROXY_ARCHITECTURE.md) for deployment guide.
## Contributing
Contributions welcome! This is an open-source project.
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing`)
5. Open a Pull Request
## Roadmap
- [x] Base blockchain integration
- [x] Solana blockchain integration
- [x] Proxy payment architecture
- [x] Automatic refunds
- [ ] Bitcoin Lightning Network support
- [ ] Distribution pool for maintainer rewards
- [ ] WebRTC support
- [ ] Advanced metering strategies
- [ ] Rate limiting
- [ ] Session resumption
- [ ] Client SDKs (JavaScript, Python, Go)
## License
MIT License - see [LICENSE](LICENSE) file
## Links
- š Website: https://ws402.org
- š¦ NPM: https://npmjs.com/package/ws402
- š¬ X: https://x.com/ws402org
- š Farcaster: https://farcaster.xyz/ws402
- š» GitHub: https://github.com/ws402/ws402
- š Documentation: https://docs.ws402.org
## Support
- š¬ GitHub Issues: https://github.com/ws402/ws402/issues
- š§ Email: support@ws402.org
- š¬ Discord: https://discord.gg/ws402
- š¦ Twitter/X: https://x.com/ws402org
## Acknowledgments
Inspired by the X402 protocol and the need for fair, pay-as-you-go pricing for WebSocket resources.
---
Built with ā¤ļø for the open web and blockchain ecosystem