anchor_parser/lib.rs
1//! # anchor-parser
2//!
3//! [](https://crates.io/crates/anchor-parser)
4//! [](https://docs.rs/anchor-parser)
5//! [](https://github.com/goni098/anchor-parser/blob/main/LICENSE)
6//!
7//! Generate Rust types and helpers from [Anchor](https://www.anchor-lang.com/) IDL
8//! JSON files using [`solana-sdk`] types directly — no `anchor-lang` dependency required.
9//!
10//! # Quick start
11//!
12//! ```toml
13//! [dependencies]
14//! anchor-parser = "2.1.0"
15//! ```
16//!
17//! Place an Anchor IDL JSON file at `<crate-root>/idls/<name>.json`, then:
18//!
19//! ```ignore
20//! anchor_parser::declare_program!(my_program);
21//! ```
22//!
23//! # Generated modules
24//!
25//! [`declare_program!`] generates a module with the following sub-modules:
26//!
27//! | Module | Contents |
28//! |--------|----------|
29//! | `accounts` | Account structs with [`AccountDeserialize`] and `from_account_data` |
30//! | `events` | Event structs with `from_logs` and `from_cpi_logs` |
31//! | `instructions` | Builder functions returning [`solana_sdk::instruction::Instruction`] |
32//! | `types` | Shared structs, enums, and type aliases from the IDL |
33//! | `constants` | Program constants with doc comments |
34//! | `utils` | `Event` / `Account` wrapper enums for generic parsing |
35//!
36//! # Examples
37//!
38//! ## Deserializing accounts
39//!
40//! ```ignore
41//! use my_program::accounts::MyAccount;
42//!
43//! // Deserialize from raw account data (discriminator + payload)
44//! let account = MyAccount::from_account_data(&raw_bytes)?;
45//!
46//! // Check discriminator
47//! assert_eq!(MyAccount::DISCRIMINATOR, [/* 8 bytes */]);
48//! ```
49//!
50//! ## Parsing events
51//!
52//! ```ignore
53//! use my_program::events::SwapEvent;
54//! use my_program::utils::Event;
55//!
56//! // Parse events from emit! log lines
57//! let events = SwapEvent::from_logs(&log_messages);
58//! let all_events = Event::from_logs(&log_messages);
59//!
60//! // Parse events from emit_cpi! inner instruction data (bs58-encoded)
61//! let events = SwapEvent::from_cpi_logs(&inner_ix_data_strings);
62//! let all_events = Event::from_cpi_logs(&inner_ix_data_strings);
63//! ```
64//!
65//! ## Building instructions
66//!
67//! ```ignore
68//! use my_program::instructions;
69//!
70//! let ix = instructions::swap(
71//! &my_program::ID,
72//! &instructions::SwapAccounts { /* ... */ },
73//! amount,
74//! min_out,
75//! )?;
76//! ```
77
78/// Generates a module from an Anchor IDL JSON file.
79///
80/// Looks for `idls/{name}.json` by walking up from `CARGO_MANIFEST_DIR`.
81///
82/// # Generated items
83///
84/// - `ID` — program [`Pubkey`](solana_sdk::pubkey::Pubkey)
85/// - `accounts` — account structs implementing [`AccountDeserialize`]
86/// - `events` — event structs with `from_logs` / `from_cpi_logs`
87/// - `instructions` — builder functions returning [`Instruction`](solana_sdk::instruction::Instruction)
88/// - `types` — shared structs, enums, and type aliases
89/// - `constants` — program constants
90/// - `utils` — `Event` / `Account` wrapper enums
91///
92/// # Example
93///
94/// ```ignore
95/// anchor_parser::declare_program!(my_program);
96///
97/// // Now use my_program::accounts, my_program::events, etc.
98/// ```
99pub use anchor_parser_macros::declare_program;
100
101/// Trait implemented by all generated account types.
102///
103/// Provides a discriminator constant and a method to deserialize from raw
104/// on-chain account data (discriminator prefix + serialized payload).
105///
106/// You generally won't need to use this trait directly — generated account
107/// types also expose a convenient `from_account_data` method.
108///
109/// # Example
110///
111/// ```ignore
112/// use anchor_parser::AccountDeserialize;
113///
114/// fn parse<T: AccountDeserialize>(data: &[u8]) -> std::io::Result<T> {
115/// T::deserialize(data)
116/// }
117/// ```
118pub trait AccountDeserialize: Sized {
119 /// The discriminator bytes that prefix this account's on-chain data.
120 const DISCRIMINATOR: &'static [u8];
121
122 /// Deserialize from raw account data (including the discriminator prefix).
123 ///
124 /// Returns an error if the data is too short, the discriminator doesn't
125 /// match, or deserialization fails.
126 fn deserialize(data: &[u8]) -> Result<Self, std::io::Error>;
127}
128
129#[doc(hidden)]
130pub mod __private {
131 pub use solana_sdk::instruction::{AccountMeta, Instruction};
132 pub use solana_sdk::pubkey::Pubkey;
133
134 pub use borsh::{BorshDeserialize, BorshSerialize};
135 pub use bytemuck::{Pod, Zeroable};
136
137 #[inline]
138 pub fn base64_decode(input: &str) -> Option<Vec<u8>> {
139 use base64::Engine;
140 base64::engine::general_purpose::STANDARD.decode(input).ok()
141 }
142
143 #[inline]
144 pub fn bs58_decode(input: &str) -> Option<Vec<u8>> {
145 bs58::decode(input).into_vec().ok()
146 }
147
148 #[inline]
149 pub fn bytemuck_read<T: bytemuck::Pod>(data: &[u8]) -> T {
150 bytemuck::pod_read_unaligned(data)
151 }
152}