ordinals_parser/
lib.rs

1//! A lightweight parser for Bitcoin Ordinals inscriptions.
2//!
3//! This library allows you to parse and extract Ordinals inscriptions from Bitcoin
4//! transactions without requiring the full Ord codebase.
5//!
6//! # Features
7//!
8//! - Parse Ordinals inscriptions from Bitcoin transactions
9//! - Support for both classic and modern inscription formats
10//! - Extract content type, body, and other metadata
11//! - Detect JSON in text/plain content
12//! - Low dependency footprint
13//!
14//! # Basic Example
15//!
16//! ```rust
17//! use ordinals_parser::{parse_inscriptions_from_transaction, Inscription};
18//! use bitcoin::Transaction;
19//!
20//! # fn example() {
21//! // Load a Bitcoin transaction
22//! let transaction: Transaction = /* ... */;
23//!     
24//! // Parse inscriptions
25//! let inscriptions = parse_inscriptions_from_transaction(&transaction);
26//!     
27//! for inscription in inscriptions {
28//!     println!("Content type: {:?}", inscription.content_type());
29//!     println!("Content length: {:?}", inscription.content_length());
30//!         
31//!     if let Some(body) = inscription.body() {
32//!         // Work with inscription content
33//!     }
34//! }
35//! # }
36//! ```
37//!
38//! # Working with JSON Inscriptions
39//!
40//! The library can detect and parse JSON content in both `application/json` and `text/plain` inscriptions:
41//!
42//! ```rust
43//! use ordinals_parser::{parse_inscriptions_from_transaction};
44//! use bitcoin::Transaction;
45//! use serde_json::Value;
46//!
47//! # fn example() {
48//! // Load a Bitcoin transaction
49//! let transaction: Transaction = /* ... */;
50//! 
51//! // Parse inscriptions
52//! let inscriptions = parse_inscriptions_from_transaction(&transaction);
53//! 
54//! for inscription in inscriptions {
55//!     if let (Some(content_type), Some(body)) = (inscription.content_type(), inscription.body()) {
56//!         // Check if it's JSON content
57//!         let is_json = content_type == "application/json" || 
58//!             (content_type.starts_with("text/plain") && 
59//!              if let Ok(text) = std::str::from_utf8(body) {
60//!                  let trimmed = text.trim();
61//!                  (trimmed.starts_with('{') && trimmed.ends_with('}')) || 
62//!                  (trimmed.starts_with('[') && trimmed.ends_with(']'))
63//!              } else {
64//!                  false
65//!              });
66//!         
67//!         if is_json {
68//!             if let Ok(text) = std::str::from_utf8(body) {
69//!                 if let Ok(json) = serde_json::from_str::<Value>(text) {
70//!                     // Process BRC-20, Ordinals Collections, etc.
71//!                     println!("Found JSON content: {:?}", json);
72//!                 }
73//!             }
74//!         }
75//!     }
76//! }
77//! # }
78//! ```
79//!
80//! # Creating an Inscription
81//!
82//! ```rust
83//! use ordinals_parser::InscriptionBuilder;
84//!
85//! # fn example() {
86//! let inscription = InscriptionBuilder::new()
87//!     .content_type("text/plain;charset=utf-8")
88//!     .body("Hello, Ordinals!".as_bytes())
89//!     .build();
90//!
91//! // Convert to a script (for inclusion in a Bitcoin transaction)
92//! let script = inscription.to_script();
93//! # }
94//! ```
95
96/// Error handling module
97pub mod error;
98
99/// Inscription envelope parsing
100pub mod envelope;
101
102/// Inscription data structure
103pub mod inscription;
104
105/// Inscription ID
106pub mod inscription_id;
107
108/// Tags used in inscriptions
109pub mod tag;
110
111// Re-export important types
112pub use crate::error::{Error, Result};
113pub use crate::inscription::{Inscription, InscriptionBuilder};
114pub use crate::inscription_id::InscriptionId;
115pub use crate::envelope::{
116    parse_transaction_inscriptions,
117    parse_input_inscriptions,
118    is_inscription_input,
119    parse_envelope,
120};
121
122/// Parse all inscriptions from a Bitcoin transaction
123///
124/// This function examines all inputs in the transaction and extracts any
125/// inscriptions found in their witness data.
126///
127/// # Parameters
128///
129/// * `tx` - A reference to a Bitcoin transaction
130///
131/// # Returns
132///
133/// A vector of `Inscription` objects found in the transaction
134///
135/// # Example
136///
137/// ```rust
138/// use ordinals_parser::parse_inscriptions_from_transaction;
139/// use bitcoin::Transaction;
140///
141/// // Load a Bitcoin transaction
142/// let transaction: Transaction = /* ... */;
143///
144/// // Parse all inscriptions
145/// let inscriptions = parse_inscriptions_from_transaction(&transaction);
146/// ```
147pub fn parse_inscriptions_from_transaction(tx: &bitcoin::Transaction) -> Vec<Inscription> {
148    envelope::parse_transaction_inscriptions(tx)
149}
150
151#[cfg(test)]
152mod tests {
153    use super::*;
154    use bitcoin::consensus::deserialize;
155    use hex::FromHex;
156
157    #[test]
158    fn test_parse_basic_inscription() {
159        // Simplified test transaction with an inscription
160        let tx_hex = "0200000000010137c361dc8bdf2c902a73c76f3059db944fc62e635ae7381aa06c79e9a1d1640b0100000000fdffffff020000000000000000296a0e6f7264010100000000000000110011018fe3bfeff84353cd5863c7c9ba48575a0cb2fb606d075f336701000000000017a914121f75e89e9b240a83b303b6e22e074d1c65dfa9870247304402205d793a28c26e568cf0601aae58a976a880f98fae56d905ab9e9e7f7342d4b3d402201b53b8f5507ac93eb7afad7e34af11c78c9b325947ad8c3f25be67700c0c0a90012103af0b2c5c872b732ac9474c576f84950e0a89ec57500507944c87f1fa4af76b9d00000000";
161        let tx_bytes = Vec::from_hex(tx_hex).unwrap();
162        let tx: bitcoin::Transaction = deserialize(&tx_bytes).unwrap();
163        
164        let inscriptions = parse_inscriptions_from_transaction(&tx);
165        
166        assert_eq!(inscriptions.len(), 1);
167        assert_eq!(inscriptions[0].content_type(), Some("text/plain"));
168        assert_eq!(inscriptions[0].body(), Some(b"Hello, world!".as_ref()));
169    }
170}