Skip to content

Generated Code Examples

This page shows complete examples of what LUMOS generates from .lumos schemas. Each example includes the input schema and both Rust and TypeScript outputs.


#[solana]
#[account]
struct PlayerAccount {
wallet: PublicKey,
level: u16,
experience: u64,
}
// Auto-generated by LUMOS
// DO NOT EDIT - Changes will be overwritten
use anchor_lang::prelude::*;
use solana_program::pubkey::Pubkey;
#[account]
pub struct PlayerAccount {
pub wallet: Pubkey,
pub level: u16,
pub experience: u64,
}

Key points:

  • #[account] macro applied (Anchor integration)
  • PublicKeyPubkey conversion
  • All fields are pub
  • No manual Borsh derives needed (handled by Anchor)
// Auto-generated by LUMOS
// DO NOT EDIT - Changes will be overwritten
import * as borsh from '@coral-xyz/borsh';
import { PublicKey } from '@solana/web3.js';
export interface PlayerAccount {
wallet: PublicKey;
level: number;
/**
* WARNING: TypeScript 'number' has precision limit of 2^53-1 (9,007,199,254,740,991).
* For Solana lamports or large values, ensure they stay within safe range.
* Values exceeding this limit will lose precision during serialization.
*/
experience: number;
}
export const PlayerAccountSchema = borsh.struct([
borsh.publicKey('wallet'),
borsh.u16('level'),
borsh.u64('experience'),
]);

Key points:

  • Interface for TypeScript type safety
  • Borsh schema for serialization/deserialization
  • u16, u64number (JavaScript safe integers)
  • Auto-generated precision warnings for u64/i64 fields

#[solana]
struct MatchResult {
winner: PublicKey,
loser: Option<PublicKey>,
score: u64,
timestamp: i64,
}
use anchor_lang::prelude::*;
pub struct MatchResult {
pub winner: Pubkey,
pub loser: Option<Pubkey>,
pub score: u64,
pub timestamp: i64,
}
impl borsh::ser::BorshSerialize for MatchResult {
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
borsh::BorshSerialize::serialize(&self.winner, writer)?;
borsh::BorshSerialize::serialize(&self.loser, writer)?;
borsh::BorshSerialize::serialize(&self.score, writer)?;
borsh::BorshSerialize::serialize(&self.timestamp, writer)?;
Ok(())
}
}
impl borsh::de::BorshDeserialize for MatchResult {
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
Ok(Self {
winner: borsh::BorshDeserialize::deserialize_reader(reader)?,
loser: borsh::BorshDeserialize::deserialize_reader(reader)?,
score: borsh::BorshDeserialize::deserialize_reader(reader)?,
timestamp: borsh::BorshDeserialize::deserialize_reader(reader)?,
})
}
}

Key differences:

  • NO #[account] macro
  • Manual Borsh trait implementations
  • Used for events, instruction arguments, return values
import { PublicKey } from '@solana/web3.js';
import * as borsh from '@coral-xyz/borsh';
export interface MatchResult {
winner: PublicKey;
loser: PublicKey | undefined;
score: number;
timestamp: number;
}
export const MatchResultSchema = borsh.struct([
borsh.publicKey('winner'),
borsh.option(borsh.publicKey(), 'loser'),
borsh.u64('score'),
borsh.i64('timestamp'),
]);

Key points:

  • Option<PublicKey>PublicKey | undefined
  • borsh.option() handles nullable fields

#[solana]
#[account]
struct Inventory {
owner: PublicKey,
items: [PublicKey],
quantities: [u32],
}
use anchor_lang::prelude::*;
#[account]
pub struct Inventory {
pub owner: Pubkey,
pub items: Vec<Pubkey>,
pub quantities: Vec<u32>,
}

Key points:

  • [T]Vec<T> in Rust
  • Dynamic-length arrays
import { PublicKey } from '@solana/web3.js';
import * as borsh from '@coral-xyz/borsh';
export interface Inventory {
owner: PublicKey;
items: PublicKey[];
quantities: number[];
}
export const InventorySchema = borsh.struct([
borsh.publicKey('owner'),
borsh.vec(borsh.publicKey(), 'items'),
borsh.vec(borsh.u32(), 'quantities'),
]);

Key points:

  • [T]T[] in TypeScript
  • borsh.vec() for dynamic arrays

#[solana]
enum GameState {
Active,
Paused { reason: String },
Finished { winner: PublicKey, score: u64 },
}
// Auto-generated by LUMOS
// DO NOT EDIT - Changes will be overwritten
use borsh::{BorshSerialize, BorshDeserialize};
use solana_program::pubkey::Pubkey;
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone)]
pub enum GameState {
Active,
Paused {
reason: String,
},
Finished {
winner: Pubkey,
score: u64,
},
}

Key points:

  • Uses #[derive] macros for automatic serialization
  • Includes Debug and Clone traits
  • Sequential discriminants (0, 1, 2…) handled by Borsh
  • Cleaner code compared to manual implementations
// Auto-generated by LUMOS
// DO NOT EDIT - Changes will be overwritten
import * as borsh from '@coral-xyz/borsh';
import { PublicKey } from '@solana/web3.js';
/**
* WARNING: Some variants contain TypeScript 'number' types with precision limit of 2^53-1.
* Large values (e.g., Solana lamports) may lose precision during serialization.
*/
export type GameState =
| { kind: 'Active' }
| { kind: 'Paused'; reason: string }
| { kind: 'Finished'; winner: PublicKey; score: number }
;
export const GameStateSchema = borsh.rustEnum([
borsh.unit('Active'),
borsh.struct([
borsh.string('reason'),
], 'Paused'),
borsh.struct([
borsh.publicKey('winner'),
borsh.u64('score'),
], 'Finished'),
]);

Key points:

  • Discriminated union type with kind field
  • TypeScript type narrowing support
  • borsh.rustEnum() for Rust-style enums

struct GenericData {
id: u64,
value: String,
metadata: Option<String>,
}

Note: No #[solana] attribute

use borsh::{BorshSerialize, BorshDeserialize};
#[derive(BorshSerialize, BorshDeserialize)]
pub struct GenericData {
pub id: u64,
pub value: String,
pub metadata: Option<String>,
}

Key differences:

  • Uses borsh crate directly (not anchor_lang)
  • #[derive] macros for serialization
  • No Solana-specific types available
import * as borsh from '@coral-xyz/borsh';
export interface GenericData {
id: number;
value: string;
metadata: string | undefined;
}
export const GenericDataSchema = borsh.struct([
borsh.u64('id'),
borsh.string('value'),
borsh.option(borsh.string(), 'metadata'),
]);

Same as Solana types - Borsh schema is identical whether #[solana] is used or not.


LUMOS intelligently chooses imports based on attributes in your entire module:

// ANY struct has #[account] → Use Anchor imports for ENTIRE module
use anchor_lang::prelude::*;
#[account]
pub struct PlayerAccount { /* ... */ }
pub struct GameEvent { /* ... */ } // Also uses Anchor imports

Scenario 2: Only #[solana] (No #[account])

Section titled “Scenario 2: Only #[solana] (No #[account])”
// Has #[solana] but no #[account] → Still use Anchor
use anchor_lang::prelude::*;
pub struct MatchResult { /* ... */ }
// Manual Borsh impls added
// Pure Borsh types
use borsh::{BorshSerialize, BorshDeserialize};
#[derive(BorshSerialize, BorshDeserialize)]
pub struct GenericData { /* ... */ }

LUMOS detects the context of your entire schema file to generate optimal code.

Input:

#[solana]
#[account]
struct PlayerAccount {
wallet: PublicKey,
level: u16,
}
#[solana]
struct GameEvent {
player: PublicKey,
action: String,
}
#[solana]
enum GameState {
Active,
Paused,
}

Generated Rust:

use anchor_lang::prelude::*;
#[account]
pub struct PlayerAccount {
pub wallet: Pubkey,
pub level: u16,
}
pub struct GameEvent {
pub player: Pubkey,
pub action: String,
}
impl borsh::ser::BorshSerialize for GameEvent { /* ... */ }
impl borsh::de::BorshDeserialize for GameEvent { /* ... */ }
pub enum GameState {
Active,
Paused,
}
impl borsh::ser::BorshSerialize for GameState { /* ... */ }
impl borsh::de::BorshDeserialize for GameState { /* ... */ }

Key insight: Since ONE type has #[account], LUMOS uses anchor_lang::prelude::* for the entire module.


use anchor_lang::prelude::*;
// Import your generated types
use crate::generated::*;
#[program]
pub mod my_game {
use super::*;
pub fn create_player(ctx: Context<CreatePlayer>) -> Result<()> {
let player = &mut ctx.accounts.player;
player.wallet = *ctx.accounts.user.key;
player.level = 1;
player.experience = 0;
Ok(())
}
}
#[derive(Accounts)]
pub struct CreatePlayer<'info> {
#[account(
init,
payer = user,
space = 8 + std::mem::size_of::<PlayerAccount>()
)]
pub player: Account<'info, PlayerAccount>, // ← Generated type
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
import { PlayerAccount, PlayerAccountSchema } from './generated';
import { PublicKey } from '@solana/web3.js';
// Serialize account data
const accountData: PlayerAccount = {
wallet: new PublicKey('...'),
level: 5,
experience: 1000,
};
const serialized = borsh.serialize(
PlayerAccountSchema,
accountData
);
// Deserialize from on-chain data
const buffer = await connection.getAccountInfo(accountAddress);
const deserialized = borsh.deserialize(
PlayerAccountSchema,
buffer.data
) as PlayerAccount;
console.log(`Level: ${deserialized.level}`);
console.log(`XP: ${deserialized.experience}`);


Generated code is automatically formatted if you have the formatters installed:

  • Rust: rustfmt (via cargo fmt)
  • TypeScript: prettier