Nostr Wallet Connect (NIP-47) implementation in PHP (nostr-php)
July 7, 2025 ยท View on GitHub
This project contains a complete client-side implementation of NIP-47 Nostr Wallet Connect for PHP, building upon nostr-php.
This project applied for the NWC Hackathon Grant on Geyser (Geyser project)
Async websocket communication is implemented using valtzu/guzzle-websocket-middleware, which is an opinionated decision and therefore the NWC functionality is provided as a separate library instead of added to the core functionality.
Overview
Nostr Wallet Connect (NWC) allows applications to connect to Lightning wallets over the Nostr protocol in a secure, decentralized way. This implementation provides:
- Client-side functionality for connecting to NWC wallet services
- Complete command support for all major Lightning operations
- Secure encryption using NIP-04 (deprecated) or NIP-44 (recommended) for wallet communications
- Comprehensive error handling with specific exception types
- Event-driven architecture following Nostr patterns
Key Features
๐ URI Parsing & Validation
- Parse and validate NWC connection URIs
- Support for multiple relays and optional Lightning addresses
- Secure parameter validation and format checking
๐ฐ Lightning Operations
- Get Balance - Check wallet balance
- Pay Invoice - Pay Lightning invoices
- Make Invoice - Create Lightning invoices
- Lookup Invoice - Query invoice status
- Get Info - Retrieve wallet capabilities
๐ Security
- NIP-04/NIP-44 encryption for wallet communications
- Proper key management and validation
- Secure event signing and verification
โก Events
- Request Events (kind 23194) - Encrypted commands to wallets
- Response Events (kind 23195) - Encrypted responses from wallets
- Info Events (kind 13194) - Public wallet capability announcements
Quick Start
1. Basic Connection
use dsbaars\nostr\Nip47\NwcClient;
use dsbaars\nostr\Nip47\NwcUri;
// Parse NWC URI
$nwcUri = 'nostr+walletconnect://wallet_pubkey?relay=wss://relay.com&secret=client_secret';
$client = new NwcClient($nwcUri);
// Check wallet capabilities
$info = $client->getWalletInfo();
echo "Supported methods: " . implode(', ', $info->getMethods());
2. Balance Check
$balance = $client->getBalance();
if ($balance->isSuccess()) {
echo "Balance: " . $balance->getBalance() . " msats";
echo "(" . $balance->getBalanceInSats() . " sats)";
}
3. Create Invoice
$invoice = $client->makeInvoice(
amount: 1000, // 1000 msats = 1 sat
description: "Test payment",
expiry: 3600 // 1 hour
);
if ($invoice->isSuccess()) {
echo "Invoice: " . $invoice->getInvoice();
echo "Payment hash: " . $invoice->getPaymentHash();
}
4. Pay Invoice
$payment = $client->payInvoice("lnbc1000n1...");
if ($payment->isPaymentSuccessful()) {
echo "Payment successful!";
echo "Preimage: " . $payment->getPreimage();
}
NIP-47 Implementation Status
This implementation provides complete coverage of the NIP-47 specification. Below are detailed tables showing all functionality and implementation status.
๐ก Event Kinds
| Kind | Description | Purpose | Implementation | Class |
|---|---|---|---|---|
| 13194 | Info Event | Wallet capability announcement | โ | InfoEvent.php |
| 23194 | Request Event | Encrypted commands to wallet | โ | RequestEvent.php |
| 23195 | Response Event | Encrypted responses from wallet | โ | ResponseEvent.php |
| 23196 | Notification Event | Real-time wallet notifications | โ | NotificationEvent.php |
๐ Commands
| Command | Description | Parameters | Implementation | Class |
|---|---|---|---|---|
get_info | Get wallet capabilities | None | โ | GetInfoCommand.php |
get_balance | Get wallet balance | None | โ | GetBalanceCommand.php |
pay_invoice | Pay Lightning invoice | invoice, amount? | โ | PayInvoiceCommand.php |
make_invoice | Create Lightning invoice | amount, description?, description_hash?, expiry? | โ | MakeInvoiceCommand.php |
lookup_invoice | Lookup invoice details | payment_hash?, invoice? | โ | LookupInvoiceCommand.php |
list_transactions | List wallet transactions | from?, until?, limit?, offset?, unpaid?, type? | โ | ListTransactionsCommand.php |
pay_keysend | Send keysend payment | amount, pubkey, preimage?, tlv_records? | โ | PayKeysendCommand.php |
multi_pay_invoice | Pay multiple invoices | invoices[] | โ | MultiPayInvoiceCommand.php |
multi_pay_keysend | Send multiple keysends | keysends[] | โ | MultiPayKeysendCommand.php |
๐จ Responses
| Response | Description | Fields | Implementation | Class |
|---|---|---|---|---|
get_info | Wallet info response | alias, color, pubkey, network, block_height, block_hash, methods[], notifications[] | โ | GetInfoResponse.php |
get_balance | Balance response | balance | โ | GetBalanceResponse.php |
pay_invoice | Payment response | preimage, fees_paid? | โ | PayInvoiceResponse.php |
make_invoice | Invoice creation response | type, invoice?, description?, description_hash?, preimage?, payment_hash, amount, fees_paid, created_at, expires_at?, metadata? | โ | MakeInvoiceResponse.php |
lookup_invoice | Invoice lookup response | type, invoice?, description?, description_hash?, preimage?, payment_hash, amount, fees_paid, created_at, expires_at?, settled_at?, metadata? | โ | LookupInvoiceResponse.php |
list_transactions | Transaction list response | transactions[] | โ | ListTransactionsResponse.php |
pay_keysend | Keysend payment response | preimage, fees_paid? | โ | PayKeysendResponse.php |
multi_pay_invoice | Multi-payment response | Multiple individual responses | โ | MultiPayInvoiceResponse.php |
multi_pay_keysend | Multi-keysend response | Multiple individual responses | โ | MultiPayKeysendResponse.php |
๐ Notifications
| Type | Description | Fields | Implementation | Class |
|---|---|---|---|---|
payment_received | Payment successfully received | type, invoice, description?, description_hash?, preimage, payment_hash, amount, fees_paid, created_at, expires_at?, settled_at, metadata? | โ | PaymentReceivedNotification.php |
payment_sent | Payment successfully sent | type, invoice, description?, description_hash?, preimage, payment_hash, amount, fees_paid, created_at, expires_at?, settled_at, metadata? | โ | PaymentSentNotification.php |
โ Error Codes
| Code | Description | When Used | Implementation |
|---|---|---|---|
RATE_LIMITED | Client sending commands too fast | Rate limiting exceeded | โ |
NOT_IMPLEMENTED | Command not known/implemented | Unsupported methods | โ |
INSUFFICIENT_BALANCE | Not enough funds available | Payment amount > balance | โ |
QUOTA_EXCEEDED | Spending quota exceeded | Budget limits reached | โ |
RESTRICTED | Operation not allowed | Permission denied | โ |
UNAUTHORIZED | No wallet connected | Invalid authorization | โ |
INTERNAL | Internal wallet error | Server-side issues | โ |
OTHER | Other unspecified error | Catch-all error | โ |
PAYMENT_FAILED | Payment processing failed | Routing/capacity issues | โ |
NOT_FOUND | Invoice not found | Invalid payment hash/invoice | โ |
๐ URI Components
| Component | Description | Required | Format | Implementation |
|---|---|---|---|---|
| Protocol | NWC protocol identifier | โ | nostr+walletconnect:// | โ |
| Pubkey | Wallet service public key | โ | 32-byte hex | โ |
relay | Relay URL(s) for communication | โ | WebSocket URL | โ |
secret | Client private key | โ | 32-byte hex | โ |
lud16 | Lightning address | โ | Lightning address format | โ |
๐ Security Features
| Feature | Description | Implementation | Notes |
|---|---|---|---|
| NIP-04 Encryption | End-to-end encryption of commands/responses | โ | Deprecated, using NIP-44 recommended |
| NIP-44 Encryption | End-to-end encryption of commands/responses | โ | All wallet communications encrypted |
| Event Signing | Cryptographic signatures on all events | โ | Prevents tampering |
| Key Isolation | Unique keys per wallet connection | โ | Improves privacy |
| Relay Authentication | Optional relay-level auth | โ | Metadata protection |
| Request Expiration | Time-bounded request validity | โ | Prevents replay attacks |
๐ฏ Advanced Features
| Feature | Description | Implementation | Class |
|---|---|---|---|
| WebSocket Communication | Real-time relay communication | โ | NwcClient.php |
| Notification Listener | Real-time payment notifications | โ | NwcNotificationListener.php |
| Multi-Command Support | Batch payment operations | โ | MultiPay*Command.php |
| Filter Management | Subscription filtering | โ | NwcClient.php |
| Connection Validation | URI and capability validation | โ | NwcUri.php |
| Error Handling | Comprehensive exception system | โ | Exception/ namespace |
| Logging Support | Configurable logging | โ | PSR-3 compatible |
Directory Structure
src/Nip47/
โโโ NwcClient.php # Main client implementation
โโโ NwcNotificationListener.php # Real-time notification listener
โโโ NwcUri.php # URI parsing and validation
โโโ NwcUriInterface.php # URI interface
โโโ ErrorCode.php # NWC error codes enum
โ
โโโ Command/ # Command implementations
โ โโโ CommandInterface.php
โ โโโ AbstractCommand.php
โ โโโ GetBalanceCommand.php # โ
get_balance
โ โโโ GetInfoCommand.php # โ
get_info
โ โโโ PayInvoiceCommand.php # โ
pay_invoice
โ โโโ MakeInvoiceCommand.php # โ
make_invoice
โ โโโ LookupInvoiceCommand.php # โ
lookup_invoice
โ โโโ ListTransactionsCommand.php # โ
list_transactions
โ โโโ PayKeysendCommand.php # โ
pay_keysend
โ โโโ MultiPayInvoiceCommand.php # โ
multi_pay_invoice
โ โโโ MultiPayKeysendCommand.php # โ
multi_pay_keysend
โ
โโโ Response/ # Response implementations
โ โโโ ResponseInterface.php
โ โโโ AbstractResponse.php
โ โโโ GetBalanceResponse.php # โ
Balance data + conversions
โ โโโ GetInfoResponse.php # โ
Wallet info + capability checks
โ โโโ PayInvoiceResponse.php # โ
Payment confirmation
โ โโโ MakeInvoiceResponse.php # โ
Invoice creation
โ โโโ LookupInvoiceResponse.php # โ
Invoice details + status
โ โโโ ListTransactionsResponse.php # โ
Transaction history
โ โโโ PayKeysendResponse.php # โ
Keysend confirmation
โ โโโ MultiPayInvoiceResponse.php # โ
Batch payment results
โ โโโ MultiPayKeysendResponse.php # โ
Batch keysend results
โ
โโโ Event/ # Nostr event implementations
โ โโโ RequestEvent.php # โ
kind 23194
โ โโโ ResponseEvent.php # โ
kind 23195
โ โโโ InfoEvent.php # โ
kind 13194
โ โโโ NotificationEvent.php # โ
kind 23196
โ
โโโ Notification/ # Notification system
โ โโโ NotificationInterface.php
โ โโโ NotificationFactory.php # โ
Factory for creating notifications
โ โโโ PaymentReceivedNotification.php # โ
payment_received
โ โโโ PaymentSentNotification.php # โ
payment_sent
โ
โโโ Exception/ # Exception hierarchy
โโโ NwcException.php
โโโ InvalidUriException.php
โโโ CommandException.php
โโโ PaymentFailedException.php
โโโ InsufficientBalanceException.php
โโโ UnauthorizedException.php
โโโ RateLimitedException.php
Examples
This project includes working examples demonstrating all NIP-47 functionality with a centralized configuration system.
Quick Start
First, configure your wallet connection:
cd examples/
cp config.php.example config.php
# Edit config.php with your actual NWC URI
Running Examples
cd examples/
# Complete wallet functionality demo
php client-example.php
# URI parsing and validation
php uri-parsing-example.php
# End-to-end payment workflow
php payment-flow-example.php
# Real-time notification listening
php notification-listener.php
# Simple wallet info and balance check
php get-info-command.php
Configuration
The examples use environment variables for easy configuration:
# Set your NWC URI
export NWC_URI="nostr+walletconnect://your-wallet-details"
# Enable verbose output
export NWC_VERBOSE=true
# Run any example
php client-example.php
Example Output
Nostr Wallet Connect Client Example
===================================
1. Parsing NWC URI...
โ Wallet Pubkey: b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4
โ Relays: wss://relay.getalby.com/v1
โ Secret: 71a8c14c...
โ Lightning Address: wallet@example.com
2. Creating NWC client...
โ Client created with pubkey: a1b2c3d4e5f6789...
3. Getting wallet info...
โ Wallet connected successfully!
- Alias: My Lightning Wallet
- Network: bitcoin
- Supported methods: get_balance, pay_invoice, make_invoice, lookup_invoice
- Supported notifications: payment_received, payment_sent
4. Getting wallet balance...
โ Balance: 100000 msats
- In sats: 100 sats
- In BTC: 0.00000100 BTC
5. Creating invoice...
โ Invoice created!
- Amount: 21000 msats
- Description: Test invoice from NWC client
- Invoice: lnbc210n1pjw8...
6. List transactions...
โ Found 5 transactions
- Incoming: 3
- Outgoing: 2
- Total amount: 150000 msats
- Total fees: 2100 msats
Example completed successfully!
Error Handling
The implementation includes comprehensive error handling:
use dsbaars\nostr\Nip47\Exception\PaymentFailedException;
use dsbaars\nostr\Nip47\Exception\InsufficientBalanceException;
try {
$payment = $client->payInvoice($invoice);
} catch (PaymentFailedException $e) {
echo "Payment failed: " . $e->getMessage();
} catch (InsufficientBalanceException $e) {
echo "Insufficient balance: " . $e->getMessage();
} catch (NwcException $e) {
echo "General NWC error: " . $e->getMessage();
}
NIP-47 Compliance
This implementation supports:
- โ All required event kinds (23194, 23195, 13194, 23196)
- โ All standard commands (get_info, get_balance, pay_invoice, make_invoice, lookup_invoice, list_transactions, pay_keysend, multi_pay_invoice, multi_pay_keysend)
- โ All notification types (payment_received, payment_sent)
- โ All error codes per specification
- โ Proper NIP-04/NIP-44 encryption
- โ URI format validation
- โ Relay communication
- โ Event signing and verification
- โ Real-time WebSocket notifications
Security Considerations
- Encryption: All communications are encrypted using NIP-04/NIP-44
- Authentication: Events are signed with client private keys
- Validation: All inputs are validated before processing
- Error Handling: Sensitive information is not leaked in errors
- Timeouts: Commands have reasonable timeout limits
- Rate Limiting: Built-in support for rate limit handling
Testing
โ ๏ธ Important: Be careful when testing with real wallets and real Bitcoin!
Running Tests
# Run all tests
php vendor/bin/phpunit tests/
# Run specific test file
php vendor/bin/phpunit tests/Nip47Test.php
Testing with Examples
- Use testnet wallets for development
- Start with small amounts - examples use 1-100 sats by default
- Configure safely - set
NWC_VERBOSE=truefor detailed output - Verify parameters before executing payments
- Check capabilities with
get-info-command.phpfirst
Test Configuration
# Use testnet amounts
export NWC_TEST_AMOUNT=1000 # 1 sat
export NWC_SMALL_AMOUNT=21000 # 21 sats
export NWC_MEDIUM_AMOUNT=100000 # 100 sats
# Enable verbose mode
export NWC_VERBOSE=true
# Test basic functionality
cd examples/
php get-info-command.php
php client-example.php
Integration
To integrate NWC into your application:
- Parse the NWC URI from user input or configuration
- Create an NwcClient instance
- Check wallet capabilities with
getWalletInfo() - Implement your payment flow using the available commands
- Handle errors gracefully with proper exception handling