anchor-parser 2.0.0

Generate Rust types and helpers from Anchor IDL JSON files using solana-sdk directly — no anchor-lang dependency
Documentation

anchor-parser

Crates.io docs.rs MIT License

Generate Rust types and helpers from Anchor IDL JSON files using solana-sdk types directly — no anchor-lang dependency required.

Features

  • Accounts — Structs with discriminator constants and deserialization (Borsh & bytemuck/zero-copy).
  • Events — Structs with from_logs (emit!) and from_cpi_logs (emit_cpi!) parsers.
  • Instructions — Builder functions that return solana_sdk::instruction::Instruction.
  • Types — Shared structs, enums, and type aliases from the IDL.
  • Constants — Program constants with doc comments.
  • UtilsEvent and Account wrapper enums for generic parsing across all program types.

Installation

[dependencies]
anchor-parser = "2.0.0"

Quick start

  1. Place an Anchor IDL JSON file in an idls/ directory at your crate root:
my-crate/
├── Cargo.toml
├── idls/
│   └── my_program.json
└── src/
    └── main.rs
  1. Declare the program:
use anchor_parser::declare_program;

declare_program!(my_program);

This generates a my_program module with the following sub-modules:

Module Contents
my_program::accounts Account structs with DISCRIMINATOR and from_account_data
my_program::events Event structs with from_logs and from_cpi_logs
my_program::instructions Builder functions → Instruction
my_program::types Shared structs, enums, type aliases
my_program::constants Program constants
my_program::utils Event / Account wrapper enums

The program ID is available as my_program::ID.

Usage

Accounts

use my_program::accounts::MyAccount;

// Deserialize from raw account data (discriminator + payload)
let account = MyAccount::from_account_data(&raw_bytes)?;

// Check discriminator
assert_eq!(MyAccount::DISCRIMINATOR, [/* 8 bytes */]);

Events

use my_program::events::SwapEvent;

// Parse events from emit! logs (base64-encoded "Program data:" log lines)
let events = SwapEvent::from_logs(&log_messages);

// Parse events from emit_cpi! inner instruction data (bs58-encoded)
let cpi_events = SwapEvent::from_cpi_logs(&inner_instruction_data);

Both methods accept any IntoIterator<Item = I> where I: AsRef<str> — vec, slice, array, iterator, &[String], &[&str], etc.

Event & Account enums

The utils module provides wrapper enums that try all known discriminators:

use my_program::utils::{Event, Account};

// Parse any program event from logs
let events: Vec<Event> = Event::from_logs(&log_messages);
let events: Vec<Event> = Event::from_cpi_logs(&log_messages);

match &events[0] {
    Event::SwapEvent(e) => println!("swap amount: {}", e.amount_0),
    Event::PoolCreatedEvent(e) => println!("new pool: {}", e.pool_state),
    _ => {}
}

// Parse any program account from raw data
let account: Account = Account::parse(&raw_bytes)?;

Instructions

use my_program::instructions;

let ix = instructions::swap(
    &my_program::ID,
    &instructions::SwapAccounts {
        payer: wallet.pubkey(),
        pool_state: pool_address,
        // ...
    },
    amount,
    min_out,
);
// ix: solana_sdk::instruction::Instruction

Constants

use my_program::constants;

let fee = constants::FEE_DENOMINATOR; // u64
let prefix = constants::POOL_PREFIX;  // &[u8]

from_logs vs from_cpi_logs

Method Source Input Decoding
from_logs emit! Transaction log messages Scans for "Program data: <base64>" lines, base64-decodes, skips 8-byte discriminator, borsh-deserializes
from_cpi_logs emit_cpi! Inner instruction data strings bs58-decodes each string, skips 16 bytes (8-byte CPI event tag + 8-byte discriminator), borsh-deserializes

Both methods share the same generic signature:

pub fn from_logs<T, I>(logs: T) -> Vec<Self>
where
    T: IntoIterator<Item = I>,
    I: AsRef<str>,

How emit_cpi! events work

Anchor's emit_cpi! emits events as self-CPI inner instructions. The instruction data is laid out as:

[8 bytes: Anchor CPI event tag] [8 bytes: event discriminator] [borsh payload]

To use from_cpi_logs, pass the bs58-encoded inner instruction data strings (not log messages) from instructions targeting your program.

Supported serialization formats

Format Accounts Events
Borsh
Bytemuck (zero-copy)
Bytemuck-unsafe (packed)

IDL compatibility

Supports the Anchor IDL JSON format. The IDL file name (without .json) becomes the Rust module name.

Tests

cargo test

The test suite covers four real-world programs (306 tests total):

Program IDL Tests
Pumpfun idls/pumpfun.json 47
Meteora DAMM v2 idls/meteora_damm_v2.json 83
Meteora DLMM idls/meteora_dlmm.json 112
Raydium CLMM idls/raydium_clmm.json 64

License

MIT