Quasar provides two account wrappers for situations where the standard validation pipeline is intentionally bypassed.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.
UncheckedAccount skips all account checks entirely, giving direct access to the raw AccountView. Uninit<A> is a parse-time placeholder for an account slot that needs to be created and initialized by the handler via a system program CPI.
UncheckedAccount
UncheckedAccount is defined with an empty check list, meaning no owner, no signer, no executable, and no data validation is performed:
#[repr(transparent)] over AccountView (via the define_account! macro), so there is no runtime overhead compared to working directly with the raw account.
When to Use UncheckedAccount
CPI passthrough
When forwarding an account to another program without inspecting its data yourself. The downstream program is responsible for validation.
Manual validation
When your validation logic is more complex than Quasar’s constraint DSL supports — for example, checking an external program’s account layout by reading raw bytes.
Destination accounts
Accounts that only receive lamports (like a close destination). No data check is needed.
External program accounts
Accounts from third-party programs whose layout Quasar doesn’t know about. Check manually after receiving them.
Accessing UncheckedAccount Data
UncheckedAccount inherits all AccountView accessors through its transparent layout. Use to_account_view() to obtain the raw view:
Escrow Example: UncheckedAccount as lamport recipient
TheTake instruction uses UncheckedAccount for the maker field because the maker receives lamports from the closed escrow but does not need to sign the take transaction:
has_one(maker) constraint on escrow ensures that maker.address() matches the stored maker address in the escrow account, so although maker is unchecked in terms of type, its identity is still validated via the constraint.
Writing Bytes to UncheckedAccount
AccountDataWrite provides a safe byte-level write operation:
AccountView and UncheckedAccount implement this trait. It validates writability and bounds before copying:
write_bytes returns ProgramError::Immutable if the account is not writable, and ProgramError::AccountDataTooSmall if the write would overflow the data region.
Uninit<A>
Uninit<A> is a parse-time marker for an account slot that must be initialized by the handler. Unlike UncheckedAccount, it does perform one validation: the account must be owned by the System program (all-zeros address). If the account is already initialized (owner is not System), parsing fails with ProgramError::AccountAlreadyInitialized.
The DeferredInit Trait
Initialization happens in the handler by calling.init(payer, params) or .init_signed(payer, params, signers). The params value must implement DeferredInit<A>:
Account<T>), the T::Target (the inner data struct) already implements DeferredInit<Account<T>> automatically. The implementation:
- Verifies the account is still owned by System
- Fetches rent from the sysvar
- Calls
create_accountCPI to allocateT::SPACEbytes and transfer lamports - Writes
T::DISCRIMINATORat the start of data - Copies the provided data into the account
- Re-validates the account as
Account<T> - Returns
&mut Account<T>
Uninit Usage
init_signed for PDA Accounts
When the new account is a PDA that must sign its own creation, useinit_signed:
In practice, most programs use the
#[account(init, payer = ...)] constraint instead of Uninit<A> directly. The constraint generates the same initialization code and is more concise. Uninit<A> is available for cases where you need fine-grained control over when and how initialization happens within the handler.