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.

Every Quasar program starts with a #[program] module. This single attribute generates the instruction dispatch table, the event authority PDA required for spoofing-resistant events, and all of the entrypoint wiring needed for the Solana runtime — all without a heap allocator or dynamic dispatch.

declare_id! and Program Identity

Before the #[program] module, call declare_id! to register your program’s on-chain address. This address becomes crate::ID and is used by the Owner trait impl generated for every #[account] type in the crate:
declare_id!("22222222222222222222222222222222222222222222");
For programs that generate a typed CPI module from an IDL, use declare_program!:
declare_program!(token, "path/to/token.json");

The #[program] Module

Annotate a mod block with #[program] and define one function per instruction inside it. Each function must be annotated with #[instruction(discriminator = N)]:
#[program]
mod quasar_escrow {
    use super::*;

    #[instruction(discriminator = 0)]
    pub fn make(ctx: Ctx<Make>, deposit: u64, receive: u64) -> Result<(), ProgramError> {
        ctx.accounts.make_escrow(receive, &ctx.bumps)?;
        ctx.accounts.emit_event(deposit, receive)?;
        ctx.accounts.deposit_tokens(deposit)
    }

    #[instruction(discriminator = 1)]
    pub fn take(ctx: Ctx<Take>) -> Result<(), ProgramError> {
        ctx.accounts.transfer_tokens()?;
        ctx.accounts.withdraw_tokens_and_close(&ctx.bumps)?;
        ctx.accounts.emit_event()
    }

    #[instruction(discriminator = 2)]
    pub fn refund(ctx: Ctx<Refund>) -> Result<(), ProgramError> {
        ctx.accounts.withdraw_tokens_and_close(&ctx.bumps)?;
        ctx.accounts.emit_event()
    }
}

What #[program] Generates

1

dispatch! router

The macro emits a dispatch! call that matches the first discriminator byte(s) of incoming instruction data against each registered handler. Account parsing runs inside the matching arm using a stack-allocated MaybeUninit<[AccountView; N]> buffer sized to the exact account count.
// Conceptual expansion of what #[program] generates
dispatch!(ptr, ix_data, 1, {
    [0] => make(Make),
    [1] => take(Take),
    [2] => refund(Refund),
    [0xFF] => __handle_event(EventAccounts),
});
2

no_alloc! + panic_handler!

Two macros set up the runtime environment for the generated entrypoint:
  • no_alloc!() registers a global allocator that calls abort_program() on any allocation attempt, enforcing the zero-allocation guarantee at runtime.
  • panic_handler!() installs a #[panic_handler] that also calls abort_program().
// Generated by #[program]
no_alloc!();
panic_handler!();
For programs that legitimately need heap access (e.g. for string formatting in tests), use heap_alloc!() in place of no_alloc!() to install a bump allocator instead.
3

Event authority PDA

The macro generates a constant EventAuthority type with a BUMP byte — the canonical __event_authority PDA derived from b"__event_authority" and the program ID. This PDA signs emit_cpi! self-CPI invocations to make events unforgeable.The __handle_event dispatch arm validates that the first account is a signer matching this PDA, then calls sol_log_data with the event payload.

Project Layout from quasar init

Running quasar init my-program scaffolds the following structure:
my-program/
├── Quasar.toml            ← project metadata and toolchain config
├── Cargo.toml
├── .cargo/config.toml     ← bpfel-unknown-none flags
└── src/
    ├── lib.rs             ← declare_id!, #[program] module
    ├── instructions/
    │   ├── mod.rs
    │   └── initialize.rs  ← starter instruction
    ├── state.rs           ← starter account type
    └── errors.rs          ← starter error enum
src/lib.rs from a freshly scaffolded project:
#![no_std]

use quasar_lang::prelude::*;

mod instructions;
use instructions::*;
mod state;
mod errors;

declare_id!("11111111111111111111111111111111");

#[program]
mod my_program {
    use super::*;

    #[instruction(discriminator = 0)]
    pub fn initialize(ctx: Ctx<Initialize>) -> Result<(), ProgramError> {
        ctx.accounts.initialize()
    }
}
src/state.rs starter:
use quasar_lang::prelude::*;

#[account(discriminator = 1)]
pub struct MyAccount {
    pub authority: Address,
    pub value: u64,
}
src/errors.rs starter:
use quasar_lang::prelude::*;

#[error_code]
pub enum MyError {
    Unauthorized,
}

Adding New Instructions with quasar add

The CLI’s quasar add instruction <name> command scaffolds a new instruction file, updates src/instructions/mod.rs, and inserts a new handler stub into the #[program] block:
quasar add instruction transfer
This creates src/instructions/transfer.rs:
use quasar_lang::prelude::*;

#[derive(Accounts)]
pub struct Transfer {
    pub payer: Signer,
    pub system_program: Program<SystemProgram>,
}

impl Transfer {
    #[inline(always)]
    pub fn transfer(&self) -> Result<(), ProgramError> {
        Ok(())
    }
}
And automatically adds to src/lib.rs:
#[instruction(discriminator = N)]
pub fn transfer(ctx: Ctx<Transfer>) -> Result<(), ProgramError> {
    ctx.accounts.transfer()
}
Discriminators are assigned automatically to the next available value.
Keep business logic in impl blocks on the accounts struct rather than directly in the #[program] function bodies. The convention keeps handlers thin — just sequenced method calls — and makes the accounts struct’s methods independently testable.

#![no_std] Requirement

All Quasar programs must declare #![no_std] at the top of lib.rs. The framework itself is a no_std crate; alloc is available when no_alloc!() is replaced with heap_alloc!(), but the standard library is never available on-chain.
#![no_std]

use quasar_lang::prelude::*;
// ...
Do not import std in any module compiled for the bpfel-unknown-none target. The Solana runtime does not provide a standard library environment; attempting to use std types produces linker errors.

Build docs developers (and LLMs) love