DocsNode Reference
SolStudio

Node Reference

Complete reference for every node type in Solana Contract Flow.


Program Node

The root node of every flow. Exactly one Program node is required per flow. It defines the top-level program metadata.

Fields

FieldTypeRequiredDescription
namestring (snake_case)YesProgram name. Becomes the Rust crate name and module name.
versionstringYesSemantic version, e.g., 0.1.0
programIdstring (base58)NoOn-chain program address. Defaults to 11111111111111111111111111111111 if not set.
descriptionstringNoHuman-readable program description
licensestringNoLicense identifier. Defaults to MIT.

Connections

  • Output (bottom): connects to Instruction nodes
  • No inputs

What It Generates

Anchor:

rust
declare_id!("ProgramIdHere");

#[program]
pub mod my_program {
    use super::*;
    // instruction entry points...
}

Pinocchio:

rust
solana_address::declare_id!("ProgramIdHere");
pinocchio::program_entrypoint!(process_instruction);

Quasar:

rust
declare_id!("ProgramIdHere");

#[program]
pub mod my_program {
    use super::*;
    // instruction logic inline...
}

Instruction Node

Represents a single instruction handler in the program. Each instruction is an entry point that clients can invoke.

Fields

FieldTypeRequiredDescription
namestring (snake_case)YesInstruction name. Becomes the Rust function name.
descriptionstringNoDocumentation for the instruction
argsInstructionArg[]NoArray of arguments passed by the client
accessControlenumNonone (default), admin_only, or custom
discriminatornumber[8]NoCustom 8-byte discriminator. Auto-generated if not set.

Instruction Arguments

Each argument has:

FieldTypeDescription
namestring (snake_case)Argument name
typeSolanaTypeSee supported types below
descriptionstringOptional documentation

Supported Types (SolanaType)

**Primitives:** bool, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64, String, Pubkey

Composites:

  • { array: [SolanaType, number] } -- fixed-size array, e.g., [u8; 32]
  • { vec: SolanaType } -- dynamic vector, e.g., Vec<u64>
  • { option: SolanaType } -- optional value, e.g., Option<Pubkey>
  • { defined: string } -- user-defined type reference
  • { hashMap: [SolanaType, SolanaType] } -- hash map
  • { enum: EnumDefinition } -- inline enum

Access Control

ModeBehavior
noneNo restrictions. Any caller can invoke.
admin_onlyOnly the program authority can invoke.
customCustom validation logic (you write the check).

Connections

  • Input (top): from Program node
  • Output right: to Account nodes
  • Output bottom: to Logic nodes and Custom Code nodes
  • Output left top: to Error nodes
  • Output left bottom: to Event nodes

What It Generates

**Anchor:** A separate file src/instructions/<name>.rs with:

rust
pub fn handler(ctx: Context<Initialize>, amount: u64) -> Result<()> {
    // logic body
    Ok(())
}

#[derive(Accounts)]
#[instruction(amount: u64)]
pub struct Initialize<'info> {
    // account fields
}

**Pinocchio:** A separate file src/instructions/<name>.rs with:

rust
pub fn process(
    program_id: &Address,
    accounts: &mut [AccountView],
    data: &[u8],
) -> ProgramResult {
    // account destructuring, validation, logic
    Ok(())
}

**Quasar:** The handler function is generated inline in src/lib.rs within the #[program] block. A separate file contains only the Accounts struct.


Account Node

Represents a Solana account passed to an instruction. This is the most configurable node type.

Account Types (14 types)

TypeDescriptionUse Case
accountA program-owned account with optional state type bindingGeneral-purpose data accounts
system-accountA system-program-owned account (has lamports, no data)Accounts you need to read but don't own
signerAn account that must sign the transactionTransaction authority, payer
programAnother on-chain program (CPI target)Cross-program invocations
token-accountAn SPL Token account (anchor_spl::token::TokenAccount)Holding SPL tokens
mintAn SPL Token mint (anchor_spl::token::Mint)Token mint accounts
associated-tokenAn Associated Token AccountDerived token accounts for users
unchecked-accountAn unvalidated AccountInfo (requires safety comment)When you need raw account access
system-programThe System program (Program<'info, System>)SOL transfers, account creation
token-programThe SPL Token programToken operations
associated-token-programThe Associated Token programCreating associated token accounts
rentThe Rent sysvar (Sysvar<'info, Rent>)Rent-exempt checks
clockThe Clock sysvar (Sysvar<'info, Clock>)Timestamps, slot numbers
customCustom-typed account with optional state bindingAny account with a custom type

Fields

FieldTypeRequiredDescription
namestring (snake_case)YesAccount identifier used in code
accountTypeAccountTypeYesOne of the 14 types above
stateTypestringNoName of the State struct this account stores
descriptionstringNoDocumentation
seedsSeedDefinition[]NoPDA seeds (when the account is a PDA)
bumpstringNoPDA bump seed

Flags

FlagEffect
isMutMarks the account as mutable. In Anchor: #[account(mut)]. In Pinocchio: generates is_writable() check.
isSignerRequires the account to be a transaction signer. In Anchor: type becomes Signer<'info>. In Pinocchio: generates is_signer() check.
isInitCreates the account during instruction execution. Requires payer and space.
isInitIfNeededCreates the account only if it doesn't exist. Requires payer and space.
isCloseCloses the account, transferring lamports to closeTarget.

Contextual Fields (appear based on accountType + flags)

**When isInit or isInitIfNeeded is set:**

FieldTypeDescription
payerstringName of the account that pays rent
spacenumber or "auto"Account data size in bytes. "auto" calculates from the bound state type.

**When isClose is set:**

FieldTypeDescription
closeTargetstringName of the account receiving the lamports

**When accountType is token-account and isInit is set:**

FieldTypeDescription
tokenAuthoritystringThe token account's owner/authority
tokenMintstringThe mint this token account is for

**When accountType is mint and isInit is set:**

FieldTypeDescription
mintAuthoritystringThe mint authority
mintDecimalsnumberToken decimals (0-9)

**When accountType is associated-token:**

FieldTypeDescription
associatedAuthoritystringThe wallet address owning this ATA
associatedMintstringThe token mint for this ATA

**When accountType is unchecked-account:**

FieldTypeDescription
safetyCommentstringRequired safety justification for using unchecked account

Connections

  • Input (top): from Instruction node
  • Output (right): to Constraint nodes
  • Input (left): from State node

PDA Seeds

When the account is a Program Derived Address, configure seeds:

Each seed has a type and value:

Seed TypeDescriptionExample
literalA static byte string"vault" generates b"vault"
account-fieldA public key from another accountauthority generates authority.key().as_ref()
instruction-argA value passed as an instruction argumentseed_id generates seed_id.as_ref()
pubkeyA public key from another accountglobal_state generates global_state.key().as_ref()

What It Generates

Anchor: Maps to typed account wrappers:

bash
accountType="signer" + isSigner  -> Signer<'info>
accountType="account" + stateType -> Account<'info, MyState>
accountType="system-program"       -> Program<'info, System>
accountType="token-account"        -> Account<'info, TokenAccount>
accountType="mint"                 -> Account<'info, Mint>
accountType="unchecked-account"    -> UncheckedAccount<'info>

**Pinocchio:** All accounts are AccountView. Validation checks are generated explicitly:

rust
if !authority.is_signer() {
    return Err(ProgramError::MissingRequiredSignature);
}
if !vault.is_writable() {
    return Err(ProgramError::InvalidAccountData);
}

Quasar: Uses reference types with mutability in the type:

rust
pub vault: &'info mut Account<Vault>,   // mut + state
pub authority: &'info Signer,            // signer
pub system_program: &'info Program<System>,  // system-program

State Node

Defines an on-chain data structure stored in program-owned accounts.

Fields

FieldTypeRequiredDescription
namestring (PascalCase)YesStruct name, e.g., Vault, UserProfile
fieldsField[]YesArray of data fields
isZeroCopybooleanNoEnable zero-copy (Pinocchio-style) access
customDiscriminatornumber[8]NoCustom 8-byte discriminator

State Fields

Each field has:

FieldTypeDescription
namestring (snake_case)Field name
typeSolanaTypeData type (see Instruction args for full list)
descriptionstringOptional documentation
maxLennumberFor dynamic types (String, Vec), the max capacity
defaultValuestringOptional default value

Connections

  • Output (right): to Account node's left (data-in) handle

What It Generates

Anchor:

rust
#[account]
#[derive(InitSpace)]
pub struct Vault {
    pub authority: Pubkey,  // 32 bytes
    pub balance: u64,       // 8 bytes
    #[max_len(64)]
    pub name: String,
}

Pinocchio: Zero-copy struct with byte-offset accessors:

rust
pub struct Vault;

impl Vault {
    pub const LEN: usize = 48; // 8 (disc) + 32 + 8
    const AUTHORITY_OFFSET: usize = 8;
    const BALANCE_OFFSET: usize = 40;

    pub fn authority(data: &[u8]) -> &Address { /* ... */ }
    pub fn set_authority(data: &mut [u8], value: &Address) { /* ... */ }
    pub fn balance(data: &[u8]) -> u64 { /* ... */ }
    pub fn set_balance(data: &mut [u8], value: u64) { /* ... */ }
}

Quasar: Pod-typed struct with explicit discriminator:

rust
#[account(discriminator = [1, 0, 0, 0, 0, 0, 0, 0])]
pub struct Vault {
    pub authority: Address,
    pub balance: PodU64,
}

Constraint Node

Adds a validation rule to an account. Constraints are alternative to flags for more granular control.

All 18 Constraint Types

1. signer

Requires the account to have signed the transaction.

Parameters: None

Generated code:

  • Anchor: Type becomes Signer<'info>
  • Pinocchio: if !account.is_signer() { return Err(...); }

2. mut

Marks the account as writable.

Parameters: None

Generated code:

  • Anchor: #[account(mut)]
  • Pinocchio: if !account.is_writable() { return Err(...); }

3. init

Creates a new account funded by a payer with the specified space.

Parameters:

ParameterTypeDescription
payerstringAccount name paying for rent
spacenumber or "auto"Account data size. "auto" uses the bound state type's INIT_SPACE.

Generated code:

  • Anchor: #[account(init, payer = payer, space = 8 + Vault::INIT_SPACE)]
  • Pinocchio: CreateAccount { payer, new_account, ... }.invoke()?;

4. init-if-needed

Creates a new account if it doesn't exist, otherwise uses the existing one.

**Parameters:** Same as init

**Note:** In Anchor, this requires the init-if-needed feature flag in Cargo.toml.

5. close

Closes the account and transfers lamports to the target.

Parameters:

ParameterTypeDescription
targetstringAccount name receiving the lamports

Generated code:

  • Anchor: #[account(close = sol_destination)]
  • Pinocchio: Manual lamport transfer + zeroing

6. has-one

Validates that a field in the account data matches another account's public key.

Parameters:

ParameterTypeDescription
fieldstringField name in the account's data
targetstringAccount name that must match
errorCodestringOptional custom error if validation fails

Generated code:

  • Anchor: #[account(has_one = authority)]
  • Pinocchio: Manual byte comparison at field offset

7. seeds

Validates the account is a valid PDA derived from the given seeds.

Parameters:

ParameterTypeDescription
seedsSeedDefinition[]Array of seeds (see Account node seeds section)
bumpstringOptional bump seed value
programIdstringOptional program ID for cross-program PDAs

Generated code:

  • Anchor: #[account(seeds = [b"vault", authority.key().as_ref()], bump)]
  • Pinocchio: crate::utils::verify_pda(account.address(), &[seeds], program_id)?;

8. owner

Validates that the account is owned by a specific program.

Parameters:

ParameterTypeDescription
ownerstringAccount name or expression for the expected owner

Generated code:

  • Anchor: #[account(owner = token_program)]
  • Pinocchio: if account.owner() != owner.address() { return Err(...); }

9. address

Validates the account's address matches an expected value.

Parameters:

ParameterTypeDescription
addressstringExpected address expression

Generated code:

  • Anchor: #[account(address = expected_pubkey)]
  • Pinocchio: Direct address comparison

10. token-authority

Validates the SPL token account's authority field.

Parameters:

ParameterTypeDescription
authoritystringAccount name expected to be the token authority

Generated code:

  • Anchor: #[account(token::authority = authority)]
  • Pinocchio: Manual byte check at offset 32

11. token-mint

Validates the SPL token account's mint field.

Parameters:

ParameterTypeDescription
mintstringAccount name expected to be the mint

Generated code:

  • Anchor: #[account(token::mint = mint)]
  • Pinocchio: Manual byte check at offset 0

12. mint-authority

Validates the mint's authority field.

Parameters:

ParameterTypeDescription
authoritystringAccount name expected to be the mint authority

Generated code:

  • Anchor: #[account(mint::authority = authority)]

13. mint-decimals

Validates the mint's decimals field.

Parameters:

ParameterTypeDescription
decimalsnumberExpected decimals value (0-9)

Generated code:

  • Anchor: #[account(mint::decimals = 9)]

14. associated-token-authority

Validates the Associated Token Account's authority.

Parameters:

ParameterTypeDescription
authoritystringAccount name expected to be the ATA owner

Generated code:

  • Anchor: #[account(associated_token::authority = authority)]

15. associated-token-mint

Validates the Associated Token Account's mint.

Parameters:

ParameterTypeDescription
mintstringAccount name expected to be the mint

Generated code:

  • Anchor: #[account(associated_token::mint = mint)]

16. realloc

Reallocates account data space.

Parameters:

ParameterTypeDescription
spacenumberNew account data size in bytes
payerstringAccount paying for the space difference
zeroInitbooleanWhether to zero-initialize new memory

Generated code:

  • Anchor: #[account(realloc = 100, realloc::payer = payer, realloc::zero = false)]

17. safety-comment

Adds a safety justification comment (for unchecked accounts or auditing).

Parameters:

ParameterTypeDescription
commentstringSafety justification text

Generated code:

  • Anchor: /// CHECK: This account is validated by the program logic
  • Pinocchio: // Safety: This account is validated by the program logic

18. custom

A custom constraint expression.

Parameters:

ParameterTypeDescription
expressionstringRust boolean expression
errorCodestringOptional custom error variant

Generated code:

  • Anchor: #[account(constraint = account.data.len() > 0 @ MyError::InvalidData)]
  • Pinocchio: if !(expression) { return Err(...); }

Error Node

Defines a custom error variant for the program.

Fields

FieldTypeRequiredDescription
namestring (PascalCase)YesError variant name, e.g., InsufficientFunds
codenumberYesError code, typically starting at 6000
messagestringYesHuman-readable error description

Connections

  • Input (left): from Instruction node's error-out handle

What It Generates

Anchor:

rust
#[error_code]
pub enum MyProgramError {
    #[msg("Insufficient funds for this operation")]
    InsufficientFunds,
}

Pinocchio:

rust
pub enum MyProgramError {
    InsufficientFunds = 6000,
}

impl From<MyProgramError> for ProgramError {
    fn from(e: MyProgramError) -> Self {
        ProgramError::Custom(e as u32)
    }
}

Quasar:

rust
#[error_code]
pub enum MyProgramError {
    InsufficientFunds = 6000,
}

Event Node

Defines an event that instructions can emit.

Fields

FieldTypeRequiredDescription
namestring (PascalCase)YesEvent struct name, e.g., TransferEvent
fieldsField[]YesArray of event data fields
descriptionstringNoDocumentation

Connections

  • Input (left): from Instruction node's event-out handle

What It Generates

Anchor:

rust
#[event]
pub struct TransferEvent {
    pub from: Pubkey,
    pub to: Pubkey,
    pub amount: u64,
}

Pinocchio:

rust
pub struct TransferEvent {
    pub from: Address,
    pub to: Address,
    pub amount: u64,
}
// Emitted via sol_log_data

Quasar:

rust
#[event(discriminator = 0)]
pub struct TransferEvent {
    pub from: Address,
    pub to: Address,
    pub amount: u64,
}

Logic Node

Defines an operation in the instruction body. This is the executable logic of your program.

All 12 Logic Operations

1. set-field

Sets a field on an account's data.

ParameterTypeDescription
accountstringAccount name to modify
fieldstringField name on the state struct
valuestringValue expression to assign

Generated code:

rust
// Anchor
vault.balance = new_amount;

// Pinocchio
Vault::set_balance(&mut vault.try_borrow_mut_data()?, new_amount);

// Quasar
vault.balance = PodU64::from(new_amount);

2. transfer-sol

Transfers SOL from one account to another.

ParameterTypeDescription
fromstringSource account name
tostringDestination account name
amountstringAmount in lamports

Generated code:

rust
// Anchor — system program CPI
anchor_lang::system_program::transfer(cpi_ctx, amount)?;

// Pinocchio — pinocchio_system
Transfer { from, to, lamports: amount }.invoke()?;

// Quasar — system program method
ctx.accounts.system_program.transfer(from, to, amount).invoke()?;

3. transfer-token

Transfers SPL tokens.

ParameterTypeDescription
fromstringSource token account
tostringDestination token account
authoritystringToken account authority (signer)
amountstringAmount in smallest units
signerSeedsSeed[]Optional PDA signer seeds for program-signed transfers

4. mint-to

Mints new tokens.

ParameterTypeDescription
mintstringMint account
tostringDestination token account
authoritystringMint authority
amountstringAmount to mint
signerSeedsSeed[]Optional PDA signer seeds

5. burn

Burns tokens.

ParameterTypeDescription
mintstringMint account
fromstringSource token account
authoritystringToken account authority
amountstringAmount to burn
signerSeedsSeed[]Optional PDA signer seeds

6. require

Validates a condition. Returns an error if the condition is false.

ParameterTypeDescription
conditionstringRust boolean expression
errorCodestringError variant name to return

Generated code:

rust
// Anchor
require!(balance >= amount, MyProgramError::InsufficientFunds);

// Pinocchio
if !(balance >= amount) {
    return Err(MyProgramError::InsufficientFunds.into());
}

// Quasar
require!(balance >= amount, MyProgramError::InsufficientFunds);

7. if-else

Conditional branching. Child logic nodes connected to this node form the "then" and "else" branches.

ParameterTypeDescription
conditionstringRust boolean expression

Child connections:

  • Connect to the default (bottom) handle for the "then" branch
  • Connect to the "else-out" handle for the "else" branch

Generated code:

rust
if condition {
    // then body
} else {
    // else body
}

8. emit-event

Emits a program event.

ParameterTypeDescription
eventstringEvent struct name
fieldsRecord<string, string>Field name to value expression mapping

Generated code:

rust
// Anchor & Quasar
emit!(TransferEvent {
    from: sender.key(),
    to: receiver.key(),
    amount: amt,
});

// Pinocchio
pinocchio::log::sol_log_data(&[&[]]);

9. return-error

Returns a custom error from the instruction.

ParameterTypeDescription
errorCodestringError variant name

Generated code:

rust
// Anchor
return err!(MyProgramError::Unauthorized);

// Pinocchio
return Err(MyProgramError::Unauthorized.into());

// Quasar
return Err(MyProgramError::Unauthorized.into());

10. math

Performs arithmetic.

ParameterTypeDescription
operationenumadd, sub, mul, div, mod
leftstringLeft operand expression
rightstringRight operand expression
resultstringVariable name to store the result
checkedbooleanIf true, uses checked arithmetic that panics on overflow

Generated code (checked):

rust
// Anchor
let result = left.checked_add(right).ok_or(ErrorCode::ArithmeticOverflow)?;

// Pinocchio & Quasar
let result = left.checked_add(right).ok_or(ProgramError::ArithmeticOverflow)?;

Generated code (unchecked):

rust
let result = left + right;

11. cpi

Cross-Program Invocation. Calls an instruction on another program.

ParameterTypeDescription
targetProgramstringAccount name of the target program
instructionstringInstruction name to call
accountsArray<{from, to}>Account mapping (your account name to CPI account name)
dataArray<{name, value}>Instruction data arguments
signerSeedsSeed[]Optional PDA signer seeds

12. custom-code

Injects raw Rust code into the instruction body.

ParameterTypeDescription
codestringRaw Rust code (multiple lines)
inputsstring[]Variable/account names this code reads
outputsstring[]Variable names this code produces

The code is inserted verbatim. Use this for logic that cannot be expressed with other node types.


Custom Code Node

A special node for injecting raw Rust code. Behaves like a Logic node but with freeform code.

Fields

FieldTypeRequiredDescription
namestringNoDisplay label
codestringYesRaw Rust code to inject
inputsstring[]NoVariable names consumed by the code
outputsstring[]NoVariable names produced by the code
descriptionstringNoDocumentation

Connections

  • Input (top): from Instruction or Logic node
  • Output (bottom): to Logic node
  • Input (left): receives variable bindings
  • Output (right): produces variable bindings

Integration Node

Plugin integration point for extending code generation with custom logic.

Fields

FieldTypeRequiredDescription
namestringYesDisplay name
pluginIdstringYesPlugin identifier
integrationIdstringYesIntegration identifier
configRecord<string, unknown>NoPlugin-specific configuration
attachedTo.instructionIdstringYesUUID of the instruction this integrates with
attachedTo.positionenumYesbefore-body, after-body, or account-level

Connections

  • Input (top): from Instruction node
  • Output (bottom): to Account node