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.

Sysvars are special Solana accounts that the runtime continuously updates with cluster-level information such as the current slot, epoch, rent rates, and timestamps. Sysvar<T> is Quasar’s zero-copy wrapper for these accounts. During account parsing it validates that the account address matches the canonical sysvar address (T::ID), then provides a Deref<Target = T> that casts directly into the sysvar account data — no heap allocation, no deserialization.

How Sysvar<T> Works

Sysvar<T> is #[repr(transparent)] over AccountView and implements AccountLoad to check the address:
impl<T: Sysvar> AccountLoad for Sysvar<T> {
    fn check(view: &AccountView) -> Result<(), ProgramError> {
        if !keys_eq(view.address(), &T::ID) {
            return Err(ProgramError::IncorrectProgramId);
        }
        Ok(())
    }
}
The Deref implementation calls T::from_bytes_unchecked on the raw account data, which is a pointer cast:
impl<T: Sysvar> Deref for Sysvar<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { T::from_bytes_unchecked(self.view.borrow_unchecked()) }
    }
}
All sysvar structs are #[repr(C)] with alignment 1, making the pointer cast sound on all targets.

Sysvar<Rent>

The Rent sysvar provides the network’s current rent parameters. These are used when creating accounts to determine the lamport balance needed for rent exemption.

Rent Struct Fields

#[repr(C)]
pub struct Rent {
    /// Rental rate in lamports per byte.
    lamports_per_byte: PodU64,

    /// Exemption threshold (stored as f64 le-bytes; compare against
    /// CURRENT_EXEMPTION_THRESHOLD or SIMD0194_EXEMPTION_THRESHOLD).
    exemption_threshold: [u8; 8],
}

Rent Methods

// Get the lamports-per-byte rate
let rate: u64 = rent.lamports_per_byte();

// Compute rent-exempt minimum balance for a given data length
// Checked: validates data_len <= 10 MiB and rate within bounds
let min: u64 = rent.try_minimum_balance(data_len)?;

// Unchecked: no overflow protection (use when you've already validated bounds)
let min: u64 = rent.minimum_balance_unchecked(data_len);

Using Rent in an Accounts Struct

// 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 rent: Sysvar<Rent>,
    pub system_program: Program<SystemProgram>,
}
When #[account(init, ...)] is present, Quasar uses the Rent sysvar internally to compute the required lamport balance. You still need to declare rent: Sysvar<Rent> in your struct so the account slot is available to the parser.

Computing Minimum Balance Manually

If you need to compute rent exemption yourself (for example, when reallocating accounts):
pub fn handler(ctx: Ctx<MyAccounts>) -> Result<(), ProgramError> {
    let rent = &*ctx.accounts.rent;  // Deref to &Rent

    // Safe: validates data_len <= 10 MiB
    let required = rent.try_minimum_balance(NEW_SPACE)?;

    // ...
    Ok(())
}

Sysvar<Clock>

The Clock sysvar provides the current cluster time. Quasar’s Clock struct captures slot, epoch, timestamps, and leader schedule epoch.

Clock Struct Fields

#[repr(C)]
pub struct Clock {
    /// Current slot number.
    pub slot: PodU64,

    /// Unix timestamp of the first slot in the current epoch.
    pub epoch_start_timestamp: PodI64,

    /// Current epoch number.
    pub epoch: PodU64,

    /// Epoch for which the next leader schedule has already been computed.
    pub leader_schedule_epoch: PodU64,

    /// Estimated Unix timestamp of the current slot (seconds since 1970-01-01).
    pub unix_timestamp: PodI64,
}
PodU64 and PodI64 are unaligned pod wrappers. Call .get() to extract the underlying integer value.

Accessing Clock Fields

use quasar_lang::prelude::*;

#[derive(Accounts)]
pub struct CheckExpiry {
    pub clock: Sysvar<Clock>,
    #[account(mut)]
    pub vault: Account<MyVault>,
}

pub fn handler(ctx: Ctx<CheckExpiry>) -> Result<(), ProgramError> {
    let clock = &*ctx.accounts.clock;  // Deref to &Clock

    let current_slot: u64       = clock.slot.get();
    let current_epoch: u64      = clock.epoch.get();
    let unix_ts: i64            = clock.unix_timestamp.get();
    let epoch_start_ts: i64     = clock.epoch_start_timestamp.get();
    let leader_sched_epoch: u64 = clock.leader_schedule_epoch.get();

    if unix_ts > ctx.accounts.vault.expiry_timestamp.get() {
        return Err(ProgramError::Custom(1)); // expired
    }

    Ok(())
}

Declaring Both Sysvars

Many instructions need both Rent (for account init) and Clock (for time-based logic):
#[derive(Accounts)]
pub struct CreateTimedVault {
    #[account(mut)]
    pub payer: Signer,
    #[account(init, payer = payer)]
    pub vault: Account<Vault>,
    pub rent: Sysvar<Rent>,
    pub clock: Sysvar<Clock>,
    pub system_program: Program<SystemProgram>,
}

When Rent Is Required

1

Account initialization

Any instruction that uses #[account(init, ...)] must include pub rent: Sysvar<Rent> in the accounts struct. Quasar reads it to calculate the rent-exempt lamport balance before calling the system program CPI.
2

Manual reallocation

When calling account.realloc(new_space, payer, Some(&*ctx.accounts.rent)), pass the Rent sysvar explicitly. If you pass None, Quasar will fetch it via a syscall instead.
3

Migration

Migration<From, To>::migrate(&payer, data) always fetches rent via syscall internally. Declaring rent: Sysvar<Rent> in a migration instruction is not required for the migrate call itself; it is only needed if your handler also performs additional account operations that require explicit rent access.
You can also obtain the current Rent or Clock via their respective Sysvar::get() syscall without passing the account in at all — but declaring the sysvar account is required when using #[account(init)] and avoids an extra syscall in rent-sensitive paths.

Build docs developers (and LLMs) love