Skip to main content

light_account_pinocchio/
lib.rs

1//! # Light Accounts Pinocchio
2//!
3//! Rent-free Light Accounts and Light Token Accounts for Pinocchio programs.
4//!
5//! ## How It Works
6//!
7//! **Light Accounts (PDAs)**
8//! 1. Create a Solana PDA normally
9//! 2. Register it with `#[derive(LightProgramPinocchio)]` - becomes a Light Account
10//! 3. Use it as normal Solana account
11//! 4. When rent runs out, account compresses (cold state)
12//! 5. State preserved on-chain, client loads when needed (hot state)
13//!
14//! **Light Token Accounts (associated token accounts, Vaults)**
15//! - Use `#[light_account(associated_token)]` for associated token accounts
16//! - Use `#[light_account(token::seeds = [...], token::owner_seeds = [...])]` for vaults
17//! - Cold/hot lifecycle
18//!
19//! **Light Mints**
20//! - Created via `invoke_create_mints`
21//! - Cold/hot lifecycle
22//!
23//! ## Quick Start
24//!
25//! ### 1. Program Setup
26//!
27//! ```rust,ignore
28//! use light_account_pinocchio::{derive_light_cpi_signer, CpiSigner, LightProgramPinocchio};
29//! use pinocchio_pubkey::pubkey;
30//!
31//! pub const ID: Pubkey = pubkey!("Your11111111111111111111111111111111111111");
32//!
33//! pub const LIGHT_CPI_SIGNER: CpiSigner =
34//!     derive_light_cpi_signer!("Your11111111111111111111111111111111111111");
35//! ```
36//!
37//! ### 2. State Definition
38//!
39//! ```rust,ignore
40//! use borsh::{BorshDeserialize, BorshSerialize};
41//! use light_account_pinocchio::{CompressionInfo, LightDiscriminator, LightHasherSha};
42//!
43//! #[derive(BorshSerialize, BorshDeserialize, LightDiscriminator, LightHasherSha)]
44//! pub struct MyRecord {
45//!     pub compression_info: CompressionInfo,  // Required first or last field
46//!     pub owner: [u8; 32],
47//!     pub data: u64,
48//! }
49//! ```
50//!
51//! ### 3. Program Accounts Enum
52//!
53//! ```rust,ignore
54//! #[derive(LightProgramPinocchio)]
55//! pub enum ProgramAccounts {
56//!     #[light_account(pda::seeds = [b"record", ctx.owner])]
57//!     MyRecord(MyRecord),
58//! }
59//! ```
60//!
61//! ## Account Types
62//!
63//! ### 1. Light Account (PDA)
64//!
65//! ```rust,ignore
66//! #[light_account(pda::seeds = [b"record", ctx.owner])]
67//! MyRecord(MyRecord),
68//! ```
69//!
70//! ### 2. Light Account (zero-copy)
71//!
72//! ```rust,ignore
73//! #[light_account(pda::seeds = [b"record", ctx.owner], pda::zero_copy)]
74//! ZeroCopyRecord(ZeroCopyRecord),
75//! ```
76//!
77//! ### 3. Light Token Account (vault)
78//!
79//! ```rust,ignore
80//! #[light_account(token::seeds = [b"vault", ctx.mint], token::owner_seeds = [b"vault_auth"])]
81//! Vault,
82//! ```
83//!
84//! ### 4. Light Token Account (associated token account)
85//!
86//! ```rust,ignore
87//! #[light_account(associated_token)]
88//! Ata,
89//! ```
90//!
91//! ## Required Derives
92//!
93//! | Derive | Use |
94//! |--------|-----|
95//! | `LightDiscriminator` | State structs (8-byte discriminator) |
96//! | `LightHasherSha` | State structs (compression hashing) |
97//! | `LightProgramPinocchio` | Program accounts enum |
98//!
99//! ## Required Macros
100//!
101//! | Macro | Use |
102//! |-------|-----|
103//! | `derive_light_cpi_signer!` | CPI signer PDA constant |
104//! | `pinocchio_pubkey::pubkey!` | Program ID as `Pubkey` |
105//!
106//! For a complete example, see `sdk-tests/pinocchio-light-program-test`.
107
108pub use pinocchio::account_info::AccountInfo;
109
110// ===== TYPE ALIASES (structs generic over AI, specialized with pinocchio AccountInfo) =====
111// Note: pinocchio's AccountInfo has no lifetime parameter, so aliases have fewer lifetimes.
112
113pub type CpiAccounts<'c> = light_sdk_types::cpi_accounts::v2::CpiAccounts<'c, AccountInfo>;
114
115pub type CompressCtx<'a> =
116    light_sdk_types::interface::program::compression::processor::CompressCtx<'a, AccountInfo>;
117
118pub type CompressDispatchFn =
119    light_sdk_types::interface::program::compression::processor::CompressDispatchFn<AccountInfo>;
120
121pub type DecompressCtx<'a> =
122    light_sdk_types::interface::program::decompression::processor::DecompressCtx<'a, AccountInfo>;
123
124pub type ValidatedPdaContext =
125    light_sdk_types::interface::program::validation::ValidatedPdaContext<AccountInfo>;
126
127pub type CpiContextWriteAccounts<'a> =
128    light_sdk_types::cpi_context_write::CpiContextWriteAccounts<'a, AccountInfo>;
129
130#[cfg(all(not(target_os = "solana"), feature = "std"))]
131pub type PackedAccounts =
132    light_sdk_types::pack_accounts::PackedAccounts<solana_instruction::AccountMeta>;
133
134// ===== RE-EXPORTED TRAITS (generic over AI, used with explicit AccountInfo in impls) =====
135
136pub use light_account_checks::close_account;
137#[cfg(feature = "token")]
138pub use light_compressed_account::instruction_data::compressed_proof::CompressedProof;
139// ===== RE-EXPORTED CONCRETE TRAITS (no AI parameter) =====
140pub use light_sdk_types::interface::account::compression_info::{
141    claim_completed_epoch_rent, CompressAs, CompressedAccountData, CompressedInitSpace,
142    CompressionInfo, CompressionInfoField, CompressionState, HasCompressionInfo, Space,
143    COMPRESSION_INFO_SIZE, OPTION_COMPRESSION_INFO_SPACE,
144};
145#[cfg(all(not(target_os = "solana"), feature = "std"))]
146pub use light_sdk_types::interface::account::pack::Pack;
147// ===== TOKEN-GATED RE-EXPORTS =====
148#[cfg(feature = "token")]
149pub use light_sdk_types::interface::account::token_seeds::{
150    PackedTokenData, TokenDataWithPackedSeeds, TokenDataWithSeeds,
151};
152// Mint creation CPI types and functions
153#[cfg(feature = "token")]
154pub use light_sdk_types::interface::cpi::create_mints::{
155    derive_mint_compressed_address as derive_mint_compressed_address_generic,
156    get_output_queue_next_index, CreateMints, CreateMintsCpi, CreateMintsParams,
157    CreateMintsStaticAccounts, SingleMintParams, DEFAULT_RENT_PAYMENT, DEFAULT_WRITE_TOP_UP,
158};
159// Token account/ATA creation CPI types and functions
160#[cfg(feature = "token")]
161pub use light_sdk_types::interface::cpi::create_token_accounts::{
162    derive_associated_token_account as derive_associated_token_account_generic,
163    CreateTokenAccountCpi, CreateTokenAccountRentFreeCpi, CreateTokenAtaCpi,
164    CreateTokenAtaCpiIdempotent, CreateTokenAtaRentFreeCpi,
165};
166// ===== RE-EXPORTED GENERIC FUNCTIONS (AI inferred from call-site args) =====
167pub use light_sdk_types::interface::cpi::invoke::invoke_light_system_program;
168#[cfg(feature = "token")]
169pub use light_sdk_types::interface::program::decompression::processor::process_decompress_accounts_idempotent;
170#[cfg(feature = "token")]
171pub use light_sdk_types::interface::program::decompression::token::prepare_token_account_for_decompression;
172#[cfg(feature = "token")]
173pub use light_sdk_types::interface::program::variant::{PackedTokenSeeds, UnpackedTokenSeeds};
174pub use light_sdk_types::interface::{
175    account::{
176        light_account::{AccountType, LightAccount},
177        pack::Unpack,
178        pda_seeds::{HasTokenVariant, PdaSeedDerivation},
179        size::Size,
180    },
181    accounts::{
182        finalize::{LightFinalize, LightPreInit},
183        init_compressed_account::{prepare_compressed_account_on_init, reimburse_rent},
184    },
185    cpi::{
186        account::CpiAccountsTrait,
187        invoke::{invoke_write_pdas_to_cpi_context, InvokeLightSystemProgram},
188        LightCpi,
189    },
190    create_accounts_proof::CreateAccountsProof,
191    program::{
192        compression::{
193            pda::prepare_account_for_compression,
194            processor::{process_compress_pda_accounts_idempotent, CompressAndCloseParams},
195        },
196        config::{
197            create::process_initialize_light_config, process_initialize_light_config_checked,
198            process_update_light_config, InitializeLightConfigParams, LightConfig,
199            UpdateLightConfigParams, LIGHT_CONFIG_SEED, MAX_ADDRESS_TREES_PER_SPACE,
200        },
201        decompression::{
202            pda::prepare_account_for_decompression,
203            processor::{
204                process_decompress_pda_accounts_idempotent, DecompressIdempotentParams,
205                DecompressVariant,
206            },
207        },
208        validation::{
209            extract_tail_accounts, is_pda_initialized, should_skip_compression,
210            split_at_system_accounts_offset, validate_compress_accounts,
211            validate_decompress_accounts,
212        },
213        variant::{IntoVariant, LightAccountVariantTrait, PackedLightAccountVariantTrait},
214    },
215    rent,
216};
217#[cfg(feature = "token")]
218pub use light_token_interface::instructions::extensions::ExtensionInstructionData as TokenExtensionInstructionData;
219// Token-interface re-exports for macro-generated code
220#[cfg(feature = "token")]
221pub use light_token_interface::instructions::extensions::TokenMetadataInstructionData;
222
223#[cfg(feature = "token")]
224pub mod token {
225    pub use light_sdk_types::interface::{
226        account::token_seeds::{
227            ExtensionInstructionData, MultiInputTokenDataWithContext, PackedTokenData,
228            TokenDataWithPackedSeeds, TokenDataWithSeeds,
229        },
230        program::decompression::token::prepare_token_account_for_decompression,
231    };
232}
233
234pub mod compression_info {
235    pub use light_sdk_types::interface::account::compression_info::*;
236}
237
238// ===== CPI / SDK-TYPES RE-EXPORTS =====
239
240pub use light_sdk_types::cpi_accounts::CpiAccountsConfig;
241
242#[cfg(all(not(target_os = "solana"), feature = "std"))]
243pub mod interface {
244    pub mod instruction {
245        pub use light_sdk_types::pack_accounts::PackedAccounts;
246    }
247}
248
249pub mod account_meta {
250    pub use light_sdk_types::instruction::account_meta::*;
251}
252
253// ===== ACCOUNT-CHECKS RE-EXPORTS (used by macro-generated code) =====
254
255pub extern crate light_account_checks;
256// ===== CONVENIENCE RE-EXPORTS =====
257pub use light_account_checks::{
258    account_info::pinocchio::OwnedAccountMeta, discriminator::Discriminator as LightDiscriminator,
259    packed_accounts, AccountInfoTrait, AccountMetaTrait,
260};
261pub use light_compressed_account::instruction_data::{
262    compressed_proof::ValidityProof, cpi_context::CompressedCpiContext,
263    with_account_info::InstructionDataInvokeCpiWithAccountInfo,
264};
265pub use light_macros::{derive_light_cpi_signer, derive_light_cpi_signer_pda, pubkey_array};
266// Re-export for macro-generated client code (off-chain only)
267#[cfg(feature = "std")]
268pub extern crate solana_instruction;
269#[cfg(feature = "std")]
270pub extern crate solana_pubkey;
271pub use light_sdk_macros::{
272    AnchorDiscriminator as Discriminator, CompressAs, HasCompressionInfo, LightAccount,
273    LightDiscriminator, LightHasher, LightHasherSha, LightPinocchioAccount, LightProgramPinocchio,
274};
275pub use light_sdk_types::{constants, error::LightSdkTypesError, instruction::*, CpiSigner};
276
277// ===== UTILITY FUNCTIONS =====
278
279/// Converts a [`LightSdkTypesError`] into a [`pinocchio::program_error::ProgramError`].
280///
281/// Use with `.map_err(light_err)` in pinocchio instruction handlers to disambiguate
282/// the multiple `From` implementations on `LightSdkTypesError`.
283pub fn light_err(e: LightSdkTypesError) -> pinocchio::program_error::ProgramError {
284    pinocchio::program_error::ProgramError::Custom(u32::from(e))
285}
286
287/// Derives the rent sponsor PDA for a given program.
288///
289/// Seeds: `["rent_sponsor"]`
290/// Returns `([u8; 32], u8)` since pinocchio uses raw byte array pubkeys.
291pub fn derive_rent_sponsor_pda(program_id: &[u8; 32]) -> ([u8; 32], u8) {
292    <AccountInfo as AccountInfoTrait>::find_program_address(
293        &[constants::RENT_SPONSOR_SEED],
294        program_id,
295    )
296}
297
298/// Find the mint PDA address for a given mint seed.
299///
300/// Returns `([u8; 32], u8)` -- the PDA address and bump.
301#[cfg(feature = "token")]
302pub fn find_mint_address(mint_seed: &[u8; 32]) -> ([u8; 32], u8) {
303    light_sdk_types::interface::cpi::create_mints::find_mint_address::<AccountInfo>(mint_seed)
304}
305
306/// Derive the compressed mint address from a mint seed and address tree pubkey.
307#[cfg(feature = "token")]
308pub fn derive_mint_compressed_address(
309    mint_seed: &[u8; 32],
310    address_tree_pubkey: &[u8; 32],
311) -> [u8; 32] {
312    derive_mint_compressed_address_generic::<AccountInfo>(mint_seed, address_tree_pubkey)
313}
314
315/// Derive the associated token account address for a given owner and mint.
316///
317/// Returns `([u8; 32], u8)` -- the ATA address and bump seed.
318#[cfg(feature = "token")]
319pub fn derive_associated_token_account(owner: &[u8; 32], mint: &[u8; 32]) -> ([u8; 32], u8) {
320    derive_associated_token_account_generic::<AccountInfo>(owner, mint)
321}