Crate star_frame

Crate star_frame 

Source
Expand description

A high-performance, trait-based Solana program framework for building fast, reliable, and type-safe programs.

Star Frame provides a modern approach to Solana program development with zero-cost abstractions, comprehensive compile-time validation, and an intuitive API design optimized for Solana’s compute unit constraints.

§Key Features

  • Type Safety: Catch errors at compile time with zero-cost abstractions
  • Performance: Optimized for Solana’s compute unit constraints
  • Developer Experience: Intuitive APIs with comprehensive validation
  • Modularity: Composable components for accounts, instructions, and program logic

§Getting Started

Add star_frame and bytemuck to your Cargo.toml:

cargo add star_frame bytemuck

§Lifecycle of a Star Frame Transaction

Here’s what happens when you call a into a Star Frame program:

§Program Entrypoint

The StarFrameProgram derive macro generates the program entrypoint:

use star_frame::prelude::*;
#[derive(StarFrameProgram)]
#[program(
    instruction_set = CounterInstructionSet,
    id = "Coux9zxTFKZpRdFpE4F7Fs5RZ6FdaURdckwS61BUTMG",
)]
pub struct CounterProgram;

The StarFrameProgram::entrypoint’s default implementation calls in to the InstructionSet::dispatch method.

§Instruction Set Dispatch

The InstructionSet derive macro defines instruction discriminants for each instruction variant (by default it is compatible with Anchor’s sighashes, but you can override it), and generates dispatch logic:

use star_frame::prelude::*;

#[derive(InstructionSet)]
pub enum CounterInstructionSet {
    Initialize(Initialize),
    Increment(Increment),
}

The derived InstructionSet::dispatch method matches on the instruction discriminant from the instruction data, and calls Instruction::process_from_raw for the matched instruction.

§Instruction Processing

The Instruction trait provides the low-level interface for instruction processing, but it’s rough and requires manual handling of raw account data and instruction bytes. In most cases, you should implement the StarFrameInstruction and InstructionArgs traits instead. The Instruction trait is implemented generically for all instructions that implement StarFrameInstruction.

Check the docs on StarFrameInstruction for how that implementation works.

§Instruction Data Parsing

Instructions implement BorshDeserialize (to parse the instruction data), and InstructionArgs (to split the data into AccountSet lifecycle arguments). See the InstructionArgs trait for more information.

use star_frame::prelude::*;
#[derive(BorshSerialize, BorshDeserialize, Debug, InstructionArgs)]
pub struct Initialize {
    #[ix_args(&run)]
    pub start_at: Option<u64>,
}

§Defining Program Accounts

Star Frame provides multiple ways to define program accounts for different use cases:

§Basic Account with Standard Derive

For statically sized accounts, you can use the ProgramAccount derive. For the best performance, you can use bytemuck (with the zero_copy macro for convenience) with Account:

use star_frame::prelude::*;

#[zero_copy(pod)]
#[derive(Default, Debug, Eq, PartialEq, ProgramAccount)]
#[program_account(seeds = CounterSeeds)]
pub struct CounterAccount {
    pub authority: Pubkey,
    pub count: u64,
}

// Strongly typed seeds can be defined too!
#[derive(Debug, GetSeeds, Clone)]
#[get_seeds(seed_const = b"COUNTER")]
pub struct CounterSeeds {
    pub authority: Pubkey,
}

You can also use borsh with BorshAccount if you don’t like need performance.

§Unsized Accounts with the Unsized Type system

For accounts with variable-size data like vectors or dynamic strings, use unsized_type.

use star_frame::prelude::*;
#[derive(Debug, GetSeeds, Clone)]

#[unsized_type(program_account, seeds = CounterSeeds)]
pub struct CounterAccount {
    pub authority: Pubkey,
    #[unsized_start]
    pub count_tracker: UnsizedMap<Pubkey, PackedValue<u64>>,
}

Check out the unsize module for more details.

§Account Set Validation

Accounts are validated through AccountSet traits with compile-time and runtime checks:

use star_frame::prelude::*;
#[derive(AccountSet)]
pub struct InitializeAccounts {
    #[validate(funder)]
    pub authority: Signer<Mut<SystemAccount>>,
    #[validate(arg = (
        Create(()),
        Seeds(CounterSeeds { authority: *self.authority.pubkey() }),
    ))]
    pub counter: Init<Seeded<Account<CounterAccount>>>,
    pub system_program: Program<System>,
}
#[derive(Align1, Pod, Zeroable, Default, Copy, Clone, Debug, Eq, PartialEq, ProgramAccount)]

§Instruction Processing

Finally, StarFrameInstruction::process executes the instruction logic:

use star_frame::prelude::*;
use star_frame::prelude::*;

impl StarFrameInstruction for Initialize {
    type Accounts<'decode, 'arg> = InitializeAccounts;
    type ReturnType = ();

    fn process(
        accounts: &mut Self::Accounts<'_, '_>,
        start_at: &Option<u64>,
        _ctx: &mut Context,
    ) -> Result<()> {
        **accounts.counter.data_mut()? = CounterAccount {
            authority: *accounts.authority.pubkey(),
            count: start_at.unwrap_or(0),
        };
        Ok(())
    }
}

You can directly implement StarFrameInstruction with the process function using the star_frame_instruction macro.

use star_frame::prelude::*;

#[star_frame_instruction]
fn Initialize(accounts: &mut InitializeAccounts, start_at: &Option<u64>) -> Result<()> {
    **accounts.counter.data_mut()? = CounterAccount {
        authority: *accounts.authority.pubkey(),
        count: start_at.unwrap_or(0),
    };
    Ok(())
}

§Putting it all together

You can check out our example programs for more information, and the simple counter example for how these steps are put together.

§Generating IDLs

Star Frame can automatically generate Codama IDL files for your programs when the idl feature flag is enabled. IDLs are JSON files that describe your program’s interface, making it easier for clients to interact with your program. Check out the Codama for more information on generating clients and using the IDL.

§Enabling IDL Generation

Add the idl feature to your Cargo.toml:

[dependencies]
star_frame = { version = "*", features = ["idl"] }

§Generating an IDL

Programs that derive StarFrameProgram automatically implement ProgramToIdl. You can create a test to generate the IDL:

#[cfg(feature = "idl")]
#[test]
fn generate_idl() -> Result<()> {
    use star_frame::prelude::*;
    let idl = CounterProgram::program_to_idl()?;
    let codama_idl: ProgramNode = idl.try_into()?;
    let idl_json = codama_idl.to_json()?;
    std::fs::write("idl.json", &idl_json)?;
    Ok(())
}

And run it with:

cargo test --features idl -- generate_idl

§Feature Flags

Star Frame provides several feature flags to customize functionality:

  • idl - Enables IDL generation for client libraries
  • test_helpers - Provides utilities for testing programs and the unsized type system
  • cleanup_rent_warning - Emits a warning message if the account has more lamports than required by rent on cleanup
  • aggressive_inline - Adds #[inline(always)] to more functions. Can be beneficial in some cases, but will likely increase binary size and may even reduce performance. This should only be used when you have thorough benchmarks and are confident in the performance impact.

Re-exports§

pub extern crate advancer;
pub extern crate borsh;
pub extern crate bytemuck;
pub extern crate derive_more;
pub extern crate derive_where;
pub extern crate fixed;
pub extern crate itertools;
pub extern crate num_traits;
pub extern crate paste;
pub extern crate pinocchio;
pub extern crate serde;
pub extern crate solana_instruction;
pub extern crate solana_pubkey;
pub extern crate self as star_frame;
pub extern crate static_assertions;
pub extern crate typenum;

Modules§

account_set
Strongly typed and statically verified instruction accounts.
align1
Alignment to 1 byte. Much of the crate::unsize magic relies on packed alignment and no padding.
client
Client-side utilities for working with Star Frame programs.
context
Context for instruction execution.
cpi
Cross program invocation (CPI) builders and utilities.
data_types
Utility data types for Star Frame programs.
errors
instruction
Processing and handling of instructions from a StarFrameProgram::entrypoint.
prelude
Commonly used types and traits: use star_frame::prelude::*.
program
Core program definitions and utilities for Star Frame programs. Provides the foundational traits and macros needed to define and execute Solana programs with type safety.
unsize
Zero-copy, dynamically sized, CU-efficient types.
util
Useful miscellaneous functions.

Macros§

bail
Returns an Err<Error>
borsh_with_bytemuck
Derives BorshSerialize and BorshDeserialize for bytemuck types.
create_unit_system
Creates a new unit system type.
ensure
Returns an Err<Error> if the condition is false
ensure_eq
Returns an Err<Error> if left is not equal to right
ensure_ne
Returns an Err<Error> if left is equal to right
error
Constructs an Error
program_setup
Defines useful top level items for a star_frame program.
pubkey
Compile time generation of a Pubkey from a base58 string literal.
sighash
Compile time hashing of string literals.
star_frame_entrypoint
Defines the entrypoint for a star_frame program.

Functions§

Ok
Equivalent to Ok::<_, Error>(value)

Type Aliases§

Result

Attribute Macros§

zero_copy
Convenience wrapper around the common bytemuck derives and repr attribute.