# NWC Client

Nostr Wallet Connect (NIP-47) client implementation for the ORLY relay. This package provides a complete client for connecting to NWC-compatible lightning wallets, enabling the relay to accept payments through the Nostr protocol.

## Features

- **NIP-47 Compliance**: Full implementation of the Nostr Wallet Connect specification
- **NIP-44 Encryption**: End-to-end encrypted communication with wallets
- **Payment Processing**: Invoice creation, payment, and balance checking
- **Real-time Notifications**: Subscribe to payment events and wallet updates
- **Error Handling**: Comprehensive error handling and recovery
- **Context Support**: Proper Go context integration for timeouts and cancellation
- **Thread Safety**: Concurrent access support with proper synchronization

## Installation

```bash
go get next.orly.dev/pkg/protocol/nwc
```

## Usage

### Basic Client Setup

```go
import "next.orly.dev/pkg/protocol/nwc"

// Create client from NWC connection URI
client, err := nwc.NewClient("nostr+walletconnect://...")
if err != nil {
    log.Fatal(err)
}
defer client.Close()
```

### Making Requests

```go
ctx := context.Background()

// Get wallet information
var info map[string]any
err = client.Request(ctx, "get_info", nil, &info)
if err != nil {
    log.Printf("Failed to get info: %v", err)
}

// Get wallet balance
var balance map[string]any
err = client.Request(ctx, "get_balance", nil, &balance)

// Create invoice
params := map[string]any{
    "amount": 1000,      // msats
    "description": "ORLY Relay Access",
}
var invoice map[string]any
err = client.Request(ctx, "make_invoice", params, &invoice)

// Check invoice status
lookupParams := map[string]any{
    "payment_hash": "abc123...",
}
var status map[string]any
err = client.Request(ctx, "lookup_invoice", lookupParams, &status)

// Pay invoice
payParams := map[string]any{
    "invoice": "lnbc10n1pj...",
}
var payment map[string]any
err = client.Request(ctx, "pay_invoice", payParams, &payment)
```

### Payment Notifications

Subscribe to real-time payment notifications:

```go
// Subscribe to payment notifications
err = client.SubscribeNotifications(ctx, func(notificationType string, notification map[string]any) error {
    switch notificationType {
    case "payment_received":
        amount := notification["amount"].(float64)
        paymentHash := notification["payment_hash"].(string)
        description := notification["description"].(string)
        log.Printf("Payment received: %.2f sats for %s", amount/1000, description)
        // Process payment...

    case "payment_sent":
        amount := notification["amount"].(float64)
        paymentHash := notification["payment_hash"].(string)
        log.Printf("Payment sent: %.2f sats", amount/1000)
        // Handle outgoing payment...

    default:
        log.Printf("Unknown notification type: %s", notificationType)
    }
    return nil
})
```

## API Reference

### Client Methods

#### `NewClient(uri string) (*Client, error)`
Creates a new NWC client from a connection URI.

#### `Request(ctx context.Context, method string, params, result any) error`
Makes a synchronous request to the wallet.

#### `SubscribeNotifications(ctx context.Context, handler NotificationHandler) error`
Subscribes to payment notifications with the provided handler function.

#### `Close() error`
Closes the client and cleans up resources.

### Supported Methods

| Method | Parameters | Description |
|--------|------------|-------------|
| `get_info` | None | Get wallet information and supported methods |
| `get_balance` | None | Get current wallet balance |
| `make_invoice` | `amount`, `description` | Create a new lightning invoice |
| `lookup_invoice` | `payment_hash` | Check status of an existing invoice |
| `pay_invoice` | `invoice` | Pay a lightning invoice |

### Notification Types

- `payment_received`: Incoming payment received
- `payment_sent`: Outgoing payment sent
- `invoice_paid`: Invoice was paid (alternative to payment_received)

## Integration with ORLY

The NWC client is integrated into the ORLY relay for payment processing:

```bash
# Enable NWC payments
export ORLY_NWC_URI="nostr+walletconnect://..."

# Start relay with payment support
./orly
```

The relay will automatically:
- Create invoices for premium features
- Validate payments before granting access
- Handle payment notifications
- Update user balances

## Error Handling

The client provides comprehensive error handling:

```go
err = client.Request(ctx, "make_invoice", params, &result)
if err != nil {
    var nwcErr *nwc.Error
    if errors.As(err, &nwcErr) {
        switch nwcErr.Code {
        case nwc.ErrInsufficientBalance:
            // Handle insufficient funds
        case nwc.ErrInvoiceExpired:
            // Handle expired invoice
        default:
            // Handle other errors
        }
    }
}
```

## Security Considerations

- **URI Protection**: Keep NWC URIs secure and don't log them
- **Context Timeouts**: Always use context with timeouts for requests
- **Error Sanitization**: Don't expose internal wallet errors to users
- **Rate Limiting**: Implement rate limiting to prevent abuse
- **Audit Logging**: Log payment operations for audit purposes

## Testing

The NWC client includes comprehensive tests:

### Running Tests

```bash
# Run NWC package tests
go test ./pkg/protocol/nwc

# Run with verbose output
go test -v ./pkg/protocol/nwc

# Run integration tests (requires wallet connection)
go test -tags=integration ./pkg/protocol/nwc
```

### Integration Testing

Part of the full test suite:

```bash
# Run all tests including NWC
./scripts/test.sh

# Run protocol package tests
go test ./pkg/protocol/...
```

### Test Coverage

Tests verify:
- Client creation and connection
- Request/response handling
- Notification subscriptions
- Error conditions and recovery
- NIP-44 encryption
- Concurrent access patterns
- Context cancellation

### Mock Testing

For testing without a real wallet:

```go
// Create mock client for testing
mockClient := nwc.NewMockClient()
mockClient.SetBalance(1000000) // 1000 sats

// Use in tests
result := make(map[string]any)
err := mockClient.Request(ctx, "get_balance", nil, &result)
```

## Examples

### Complete Payment Flow

```go
package main

import (
    "context"
    "log"
    "time"

    "next.orly.dev/pkg/protocol/nwc"
)

func main() {
    client, err := nwc.NewClient("nostr+walletconnect://...")
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    // Get wallet info
    var info map[string]any
    if err := client.Request(ctx, "get_info", nil, &info); err != nil {
        log.Printf("Failed to get info: %v", err)
        return
    }
    log.Printf("Connected to wallet: %v", info)

    // Create invoice
    invoiceParams := map[string]any{
        "amount": 5000,  // 5 sats
        "description": "Test payment",
    }

    var invoice map[string]any
    if err := client.Request(ctx, "make_invoice", invoiceParams, &invoice); err != nil {
        log.Printf("Failed to create invoice: %v", err)
        return
    }

    bolt11 := invoice["invoice"].(string)
    log.Printf("Created invoice: %s", bolt11)

    // In a real application, you would present this invoice to the user
    // For testing, you can pay it using the same client
    payParams := map[string]any{"invoice": bolt11}
    var payment map[string]any
    if err := client.Request(ctx, "pay_invoice", payParams, &payment); err != nil {
        log.Printf("Failed to pay invoice: %v", err)
        return
    }

    log.Printf("Payment successful: %v", payment)
}
```

### Notification Handler

```go
func setupPaymentHandler(client *nwc.Client) {
    ctx := context.Background()

    err := client.SubscribeNotifications(ctx, func(notificationType string, notification map[string]any) error {
        log.Printf("Received notification: %s", notificationType)

        switch notificationType {
        case "payment_received":
            // Grant access to paid feature
            userID := notification["description"].(string)
            amount := notification["amount"].(float64)
            grantPremiumAccess(userID, amount)

        case "payment_sent":
            // Log outgoing payment
            amount := notification["amount"].(float64)
            log.Printf("Outgoing payment: %.2f sats", amount/1000)

        default:
            log.Printf("Unknown notification type: %s", notificationType)
        }

        return nil
    })

    if err != nil {
        log.Printf("Failed to subscribe to notifications: %v", err)
    }
}
```

## Development

### Building

```bash
go build ./pkg/protocol/nwc
```

### Code Quality

- Comprehensive error handling
- Go context support
- Thread-safe operations
- Extensive test coverage
- Proper resource cleanup

## Troubleshooting

### Common Issues

1. **Connection Failed**: Check NWC URI format and wallet availability
2. **Timeout Errors**: Use context with appropriate timeouts
3. **Encryption Errors**: Verify NIP-44 implementation compatibility
4. **Notification Issues**: Check wallet support for notifications

### Debugging

Enable debug logging:

```bash
export ORLY_LOG_LEVEL=debug
```

Monitor relay logs for NWC operations.

## License

Part of the next.orly.dev project. See main LICENSE file.
