1 unstable release
Uses new Rust 2024
| 0.1.0 | Oct 27, 2025 |
|---|
#1 in #payjoin
28KB
381 lines
unified_uri
A Rust library for parsing unified Bitcoin URIs that support both Lightning Network invoices and Payjoin parameters, based on the BIP21 URI specification.
Overview
This crate extends the BIP21 URI standard to support unified QR codes that contain both on-chain Bitcoin addresses and Lightning Network payment information, as well as Payjoin parameters. This enables a single QR code to work with both on-chain and Lightning wallets, eliminating the need for separate payment interfaces.
Features
- Lightning Network Support: Parse BOLT11 invoices from BIP21 URIs using the
lightningparameter - Payjoin Integration: Support for payjoin endpoints (
pj) and output substitution control (pjos) - Backwards Compatible: Works with standard BIP21 URIs (on-chain only)
- Security: Validates payjoin endpoints to ensure they use secure protocols (HTTPS or .onion domains)
Usage
Add this to your Cargo.toml:
[dependencies]
unified_uri = "0.1"
Basic Example
use unified_uri::UnifiedUri;
use std::str::FromStr;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Parse a unified URI with Lightning and Payjoin support
let uri_str = "bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?pj=https://payjoin.example.com/payjoin&pjos=1";
let uri = UnifiedUri::from_str(uri_str)?;
// Access the Bitcoin address
println!("Address: {}", uri.address);
// Access Lightning invoice if present
if let Some(invoice) = &uri.extras.lightning {
println!("Lightning Invoice: {:?}", invoice);
}
// Access Payjoin parameters
if let Some(pj_url) = &uri.extras.pj {
println!("Payjoin endpoint: {}", pj_url);
}
// Check if output substitution is disabled
if uri.extras.disable_output_substitution() {
println!("Payjoin output substitution is disabled");
}
Ok(())
}
Building URIs
use unified_uri::UnifiedUriBuilder;
use bitcoin::{Address, Amount};
use std::str::FromStr;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a valid Bitcoin address
let address: Address = "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlhfe2".parse()?;
// Build a basic on-chain URI
let basic_uri = UnifiedUriBuilder::new(address.clone()).build();
println!("{}", basic_uri); // "bitcoin:bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlhfe2"
// Build a full unified URI with all parameters
let unified_uri = UnifiedUriBuilder::new(address)
.amount(Amount::from_sat(100_000)?) // 0.001 BTC in satoshis
.label("Payment for services")
.message("Thank you for your business")
.lightning("lnbc10u1p3pj257pp5yz...") // or use lightning_invoice(parsed_invoice)
.payjoin_url("https://payjoin.example.com/payjoin")
.disable_output_substitution(true)
.build();
println!("{}", unified_uri);
// "bitcoin:bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlhfe2?amount=0.001&label=Payment%20for%20services&message=Thank%20you%20for%20your%20business&lightning=lnbc10u1p3pj257pp5yz...&pj=https://payjoin.example.com/payjoin&pjos=1"
Ok(())
}
Parsing Different URI Types
use unified_uri::UnifiedUri;
// On-chain only (standard BIP21)
let onchain_uri = "bitcoin:1andreas3batLhQa2FawWjeyjCqyBzypd";
// With Lightning invoice
let lightning_uri = "bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?lightning=LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6";
// With Payjoin parameters
let payjoin_uri = "bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?pj=https://payjoin.example.com/payjoin&pjos=1";
// All three can be parsed with UnifiedUri
let unified_uri = UnifiedUri::from_str(lightning_uri)?;
BIP21 Parameters Supported
| Parameter | Type | Description |
|---|---|---|
lightning |
String | BOLT11 Lightning invoice |
pj |
String | Payjoin endpoint URL |
pjos |
String | Payjoin output substitution (0 = enabled, 1 = disabled) |
Unified QR Codes
This crate enables the creation and parsing of unified QR codes as described in the Unified QR Code specification. These QR codes allow a single payment request to work with:
- On-chain only wallets: Ignore Lightning and Payjoin parameters
- Lightning wallets: Use the Lightning invoice when present
- Payjoin-compatible wallets: Use the Payjoin endpoint for enhanced privacy
API Reference
UnifiedUri<'a>
The main type for parsing unified BIP21 URIs. This is a type alias for Uri<'a, NetworkUnchecked, UnifiedExtras>.
UnifiedExtras
Contains the extra parameters parsed from the URI:
lightning: Option<Bolt11Invoice>- Lightning invoice if presentpj: Option<Url>- Payjoin endpoint URL if presentpjos: Option<bool>- Payjoin output substitution setting
Methods
disable_output_substitution() -> bool- Returnstrueif payjoin output substitution should be disabled
UnifiedUriBuilder
Builder for creating unified BIP21 URI strings with optional Lightning and Payjoin parameters.
Methods
new(address: Address) -> Self- Create a new builder instance with required Bitcoin addressamount(self, amount: Amount) -> Self- Set the payment amount in satoshislabel<S: Into<String>>(self, label: S) -> Self- Set the payment labelmessage<S: Into<String>>(self, message: S) -> Self- Set the payment messagelightning_invoice(self, invoice: Bolt11Invoice) -> Self- Set the Lightning invoice from Bolt11Invoice structlightning<S: Into<String>>(self, invoice: S) -> Self- Set the Lightning invoice from stringpayjoin_url<S: Into<String>>(self, url: S) -> Self- Set the Payjoin endpoint URL from stringpayjoin(self, url: Url) -> Self- Set the Payjoin endpoint URL from Url structdisable_output_substitution(self, disable: bool) -> Self- Set whether to disable output substitutionbuild(self) -> String- Build the final URI string
Security Considerations
- Payjoin endpoints are validated to ensure they use secure protocols (HTTPS or .onion domains)
- Malformed Lightning invoices will result in parsing errors
- Multiple parameters of the same type are not allowed and will cause errors
Dependencies
bip21- BIP21 URI parsingbitcoin- Bitcoin address handlinglightning-invoice- BOLT11 invoice parsingurl- URL validation
References
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License.
Dependencies
~10MB
~152K SLoC