nova-carnivore / bolt11-php
Modern PHP 8.3+ BOLT 11 Lightning Network invoice encoder/decoder
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/nova-carnivore/bolt11-php
Requires
- php: ^8.3
- ext-gmp: *
- paragonie/ecc: ^2.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
README
Modern PHP 8.3+ BOLT 11 Lightning Network invoice encoder/decoder. Full spec compliance, production-ready.
Features
- โก Full BOLT 11 spec compliance โ All 12 spec test vectors pass
- ๐ Encode, sign & decode โ Complete lifecycle support
- ๐๏ธ Modern PHP 8.3+ โ Enums, readonly classes, named arguments, match expressions
- ๐ PHPStan level 9 โ Maximum static analysis strictness
- ๐ All networks โ Bitcoin, Testnet, Signet, Regtest
- ๐ท๏ธ All tag types โ payment_hash, description, route hints, feature bits, metadata, and more
- ๐ Round-trip safe โ Encode โ sign โ decode preserves all data
- ๐ PSR-12 code style โ Enforced with PHP-CS-Fixer
- ๐ Security-hardened crypto โ Uses paragonie/ecc with constant-time operations
Installation
composer require nova-carnivore/bolt11-php
Requirements
- PHP 8.3 or higher
- ext-gmp (required by paragonie/ecc)
Quick Start
Decode an Invoice
use Nova\Bitcoin\Bolt11\Decoder; $invoice = Decoder::decode('lnbc2500u1pvjluez...'); $invoice->satoshis; // 250000 $invoice->millisatoshis; // '250000000' $invoice->network; // Network::Bitcoin $invoice->timestamp; // 1496314658 $invoice->payeeNodeKey; // '03e7156ae33b...' // Access tags $invoice->getPaymentHash(); // hex string $invoice->getDescription(); // 'string' $invoice->getPaymentSecret(); // hex string $invoice->isExpired(); // bool $invoice->getTag('payment_hash'); // Tag object
Encode an Invoice
use Nova\Bitcoin\Bolt11\Encoder; use Nova\Bitcoin\Bolt11\Network; use Nova\Bitcoin\Bolt11\Tag; $unsigned = Encoder::encode( network: Network::Bitcoin, satoshis: 1000, tags: [ Tag::paymentHash('0001020304050607...'), Tag::paymentSecret('1111111111111111...'), Tag::description('test payment'), Tag::expiry(3600), ], );
Sign an Invoice
use Nova\Bitcoin\Bolt11\Signer; $signed = Signer::sign($unsigned, $privateKeyHex); $signed->paymentRequest; // 'lnbc10u1...' $signed->complete; // true $signed->payeeNodeKey; // compressed public key
Amount Helpers
use Nova\Bitcoin\Bolt11\Helpers; Helpers::satToHrp(250000); // '2500u' Helpers::hrpToSat('2500u'); // '250000' Helpers::millisatToHrp('1000'); // '10n' Helpers::hrpToMillisat('10n'); // '1000'
API Reference
Decoder::decode(string $paymentRequest): Invoice
Decodes a BOLT 11 payment request string into an Invoice object. Handles both lowercase and UPPERCASE invoices.
Encoder::encode(...): Invoice
Creates an unsigned invoice. Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
network |
Network |
Network::Bitcoin |
Target network |
satoshis |
?int |
null |
Amount in satoshis |
millisatoshis |
?string |
null |
Amount in millisatoshis |
tags |
array<Tag> |
[] |
Tagged fields |
timestamp |
?int |
null |
Unix timestamp (defaults to now) |
Signer::sign(Invoice $invoice, string $privateKeyHex): Invoice
Signs an unsigned invoice with a secp256k1 private key.
Invoice (Value Object)
| Property | Type | Description |
|---|---|---|
complete |
bool |
Whether the invoice is fully signed |
prefix |
string |
Full HRP (e.g. lnbc2500u) |
network |
?Network |
Bitcoin network enum |
satoshis |
?int |
Amount in satoshis |
millisatoshis |
?string |
Amount in millisatoshis |
timestamp |
int |
Unix timestamp |
payeeNodeKey |
?string |
Compressed public key (hex) |
signature |
string |
64-byte compact signature (hex) |
recoveryFlag |
int |
Signature recovery flag (0-3) |
tags |
array<Tag> |
All tagged fields |
paymentRequest |
?string |
Full bech32-encoded string |
Tag Factory Methods
Tag::paymentHash(string $hex): Tag Tag::paymentSecret(string $hex): Tag Tag::description(string $text): Tag Tag::descriptionHash(string $hex): Tag Tag::payeeNodeKey(string $hex): Tag Tag::expiry(int $seconds): Tag Tag::minFinalCltvExpiry(int $blocks): Tag Tag::fallbackAddress(int $code, string $addressHash): Tag Tag::routeHint(array $hops): Tag Tag::featureBits(FeatureBits $bits): Tag Tag::metadata(string $hex): Tag
Enums
enum Network: string { case Bitcoin = 'bc'; case Testnet = 'tb'; case Signet = 'tbs'; case Regtest = 'bcrt'; } enum TagType: int { case PaymentHash = 1; case PaymentSecret = 16; case Description = 13; // ... and more } enum Multiplier: string { case Milli = 'm'; case Micro = 'u'; case Nano = 'n'; case Pico = 'p'; }
BOLT 11 Spec Compliance
All 12 official test vectors pass:
| # | Test | Status |
|---|---|---|
| 1 | Donation (any amount) | โ |
| 2 | $3 coffee (2500ยต, 60s expiry) | โ |
| 3 | UTF-8 description (ใใณใปใณใน 1ๆฏ) | โ |
| 4 | Hashed description (20m) | โ |
| 5 | Testnet with P2PKH fallback | โ |
| 6 | Mainnet with P2PKH + route hints | โ |
| 7 | Feature bits (8, 14, 99) | โ |
| 8 | Uppercase invoice | โ |
| 9 | Metadata (0x01fafaf0) | โ |
| 10 | Pico-BTC amount (9678785340p) | โ |
| 11 | High-S signature recovery | โ |
| 12 | Unknown tags (silently ignored) | โ |
Supported Tagged Fields
| Code | Letter | Field | Supported |
|---|---|---|---|
| 1 | p |
payment_hash | โ |
| 16 | s |
payment_secret | โ |
| 13 | d |
description | โ |
| 27 | m |
metadata | โ |
| 19 | n |
payee node key | โ |
| 23 | h |
description_hash | โ |
| 6 | x |
expiry | โ |
| 24 | c |
min_final_cltv_expiry | โ |
| 9 | f |
fallback address | โ |
| 3 | r |
route hints | โ |
| 5 | 9 |
feature bits | โ |
Exception Handling
use Nova\Bitcoin\Bolt11\Exception\{ Bolt11Exception, // Base exception InvalidInvoiceException, // Malformed invoice InvalidChecksumException, // Bad bech32 checksum InvalidSignatureException, // Signature issues InvalidAmountException, // Bad amount format UnsupportedNetworkException, // Unknown network }; try { $invoice = Decoder::decode($paymentRequest); } catch (InvalidChecksumException $e) { // Bad checksum } catch (InvalidInvoiceException $e) { // Malformed invoice } catch (Bolt11Exception $e) { // Any BOLT 11 error }
Development
# Install dependencies composer install # Run tests vendor/bin/phpunit # Static analysis vendor/bin/phpstan analyse # Code style check vendor/bin/php-cs-fixer fix --dry-run --diff # Fix code style vendor/bin/php-cs-fixer fix
Architecture
src/
โโโ Decoder.php # Main decoder
โโโ Encoder.php # Main encoder
โโโ Signer.php # Invoice signing (secp256k1)
โโโ Secp256k1Recovery.php # ECDSA public key recovery
โโโ Invoice.php # Immutable value object
โโโ Tag.php # Tag value object with factory methods
โโโ TagType.php # Tag type enum
โโโ Network.php # Network enum (Bitcoin, Testnet, Signet, Regtest)
โโโ Multiplier.php # Amount multiplier enum (m, u, n, p)
โโโ Amount.php # Amount value object
โโโ RouteHint.php # Route hint value object
โโโ FallbackAddress.php # Fallback address value object
โโโ FeatureBits.php # Feature bits handler
โโโ Bech32.php # Bech32 encoder/decoder
โโโ Helpers.php # Static helper methods
โโโ Exception/
โโโ Bolt11Exception.php
โโโ InvalidInvoiceException.php
โโโ InvalidChecksumException.php
โโโ InvalidSignatureException.php
โโโ InvalidAmountException.php
โโโ UnsupportedNetworkException.php
License
MIT โ see LICENSE.