Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/blueshift-gg/quasar/llms.txt

Use this file to discover all available pages before exploring further.

Program<T> is Quasar’s typed wrapper for program accounts. During account parsing it validates two things: the executable flag must be set in the SVM account header, and the account’s address must exactly equal T::ID. If either check fails, parsing returns ProgramError::IncorrectProgramId. The wrapper is then #[repr(transparent)] over AccountView, giving zero-cost access to the underlying program account.

What Program<T> Validates

The Program<T> AccountLoad implementation enforces both checks:
impl<T: Id> AccountLoad for Program<T> {
    const IS_EXECUTABLE: bool = true;  // causes generated parser to check executable flag

    fn check(view: &AccountView) -> Result<(), ProgramError> {
        if !keys_eq(view.address(), &T::ID) {
            return Err(ProgramError::IncorrectProgramId);
        }
        Ok(())
    }
}
IS_EXECUTABLE = true causes the generated account-parsing code to assert view.executable() before calling check. The check body then compares the address against T::ID.

The Id Trait

T must implement Id, which simply provides a compile-time address constant:
pub trait Id {
    const ID: Address;
}
Any type with an impl Id can be used as the type parameter for Program<T>. For convenience, Quasar provides built-in program marker types.

Built-in Program Markers

SystemProgram

ID = 11111111111111111111111111111111Used for account creation, lamport transfers, and allocation. Program<SystemProgram> also has helper methods like create_account() and transfer().

TokenProgram

ID = TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DASPL Token program. Program<TokenProgram> implements TokenCpi for typed token operations.

Token2022Program

ID = TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEbToken Extensions (Token-2022) program. Program<Token2022Program> also implements TokenCpi.

Usage in Accounts Structs

Declare program accounts without #[account(mut)] — programs are always read-only:
// From examples/escrow/src/instructions/make.rs
#[derive(Accounts)]
pub struct Make {
    #[account(mut)]
    pub maker: Signer,
    #[account(init, payer = maker, address = Escrow::seeds(maker.address()))]
    pub escrow: Account<Escrow>,
    pub mint_a: Account<Mint>,
    pub mint_b: Account<Mint>,
    // ...
    pub token_program: Program<TokenProgram>,
    pub system_program: Program<SystemProgram>,
}

Getting the Program ID

Program<T> implements Id, so T::ID is always available at compile time. At runtime, you can also retrieve the program’s address through AsAccountView:
// Compile-time constant
let id: Address = TokenProgram::ID;

// Runtime via AsAccountView (same value, from the live account)
let id: &Address = ctx.accounts.token_program.address();

Calling CPIs via Program Methods

Program<SystemProgram> and Program<TokenProgram> expose strongly-typed CPI builder methods:
// Transfer tokens via SPL Token CPI
pub fn deposit_tokens(&mut self, amount: u64) -> Result<(), ProgramError> {
    self.token_program
        .transfer(&self.maker_ta_a, &self.vault_ta_a, &self.maker, amount)
        .invoke()
}
The .invoke() call at the end dispatches the CPI. For PDA-signed CPIs use .invoke_signed(&seeds) instead.

Interface<T> for Multiple Programs

When an instruction must accept either SPL Token or Token-2022, use Interface<T> with a ProgramInterface marker type instead of Program<T>:
use quasar_spl::interface::TokenInterface;

#[derive(Accounts)]
pub struct FlexibleTransfer {
    // Accepts either TokenProgram or Token2022Program
    pub token_program: Interface<TokenInterface>,
}
Interface<T> requires T: ProgramInterface, which provides a matches(address: &Address) -> bool method. Quasar calls this at parse time instead of a single address equality check:
pub struct TokenInterface;

impl ProgramInterface for TokenInterface {
    fn matches(address: &Address) -> bool {
        keys_eq(address, &SPL_TOKEN_ID) || keys_eq(address, &TOKEN_2022_ID)
    }
}

InterfaceAccount<T> for Multi-Owner Accounts

For data accounts that may be owned by any program in an interface set (for example, a token account owned by either TokenProgram or Token2022Program), use InterfaceAccount<T>:
// T must implement Owners (returns a static slice of valid owner addresses)
pub struct InterfaceAccount<T> { ... }
InterfaceAccount<T> validates the owner against T::owners() at parse time. It supports the same zero-copy Deref/DerefMut as Account<T>.

ProgramInterface for Custom Interfaces

Implement ProgramInterface on your own marker type to create custom multi-program interfaces:
pub struct MyOracleInterface;

impl ProgramInterface for MyOracleInterface {
    fn matches(address: &Address) -> bool {
        keys_eq(address, &ORACLE_V1_ID) || keys_eq(address, &ORACLE_V2_ID)
    }
}

#[derive(Accounts)]
pub struct ReadPrice {
    pub oracle_program: Interface<MyOracleInterface>,
}

emit_event via Program

Program<T> also provides an emit_event method for self-CPI event emission, used when the instruction includes an event authority account:
pub fn emit_event<E, EA>(
    &self,
    event: &E,
    event_authority: &EA,
    bump: u8,
) -> Result<(), ProgramError>
where
    E: Event,
    EA: AsAccountView,
Always pass the correct program account for every CPI you perform. Quasar validates the program address at parse time, but if you hand-construct a CPI via CpiCall you are responsible for ensuring the program ID is correct.

Build docs developers (and LLMs) love