- Light token accounts are Solana accounts that hold token balances of light, SPL, or Token 2022 mints.
- Light token accounts are on-chain accounts like SPL ATA’s, but the light token program sponsors the rent-exemption cost for you.
Light Rent Config Explained
Light Rent Config Explained
- The rent-exemption for light account creation is sponsored by the Light Token Program.
- Transaction payer’s pay rent
to keep accounts “active” - “Inactive” accounts (rent below one epoch) get automatically compressed.
- The account’s state is cryptographically preserved and will be loaded into hot account state in-flight, when the account is used again.
- At account creation ~17,208 lamports
and . - When the account’s rent is below 3h, the transaction payer tops up 776 lamports.
- Rust Client
- Program Guide
CreateTokenAccount creates an on-chain token account to store token balances of light, SPL, or Token 2022 mints.Compare to SPL:1
Prerequisites
Dependencies
Dependencies
Cargo.toml
Report incorrect code
Copy
Ask AI
[dependencies]
light-compressed-token-sdk = "0.1"
light-client = "0.1"
light-token-types = "0.1"
solana-sdk = "2.2"
borsh = "0.10"
tokio = { version = "1.36", features = ["full"] }
[dev-dependencies]
light-program-test = "0.1" # For in-memory tests with LiteSVM
Developer Environment
Developer Environment
- In-Memory (LightProgramTest)
- Localnet (LightClient)
- Devnet (LightClient)
Test with Lite-SVM (…)
Report incorrect code
Copy
Ask AI
# Initialize project
cargo init my-light-project
cd my-light-project
# Run tests
cargo test
Report incorrect code
Copy
Ask AI
use light_program_test::{LightProgramTest, ProgramTestConfig};
use solana_sdk::signer::Signer;
#[tokio::test]
async fn test_example() {
// In-memory test environment
let mut rpc = LightProgramTest::new(ProgramTestConfig::default())
.await
.unwrap();
let payer = rpc.get_payer().insecure_clone();
println!("Payer: {}", payer.pubkey());
}
Connects to a local test validator.
- npm
- yarn
- pnpm
Report incorrect code
Copy
Ask AI
npm install -g @lightprotocol/zk-compression-cli@alpha
Report incorrect code
Copy
Ask AI
yarn global add @lightprotocol/zk-compression-cli@alpha
Report incorrect code
Copy
Ask AI
pnpm add -g @lightprotocol/zk-compression-cli@alpha
Report incorrect code
Copy
Ask AI
# Initialize project
cargo init my-light-project
cd my-light-project
# Start local test validator (in separate terminal)
light test-validator
Report incorrect code
Copy
Ask AI
use light_client::rpc::{LightClient, LightClientConfig, Rpc};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Connects to http://localhost:8899
let rpc = LightClient::new(LightClientConfig::local()).await?;
let slot = rpc.get_slot().await?;
println!("Current slot: {}", slot);
Ok(())
}
Replace
<your-api-key> with your actual API key. Get your API key here.Report incorrect code
Copy
Ask AI
use light_client::rpc::{LightClient, LightClientConfig, Rpc};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let rpc_url = "https://devnet.helius-rpc.com?api-key=<your_api_key>";
let rpc = LightClient::new(
LightClientConfig::new(rpc_url.to_string(), None, None)
).await?;
println!("Connected to Devnet");
Ok(())
}
2
Create Token Account
View Source Code or find full examples with tests: examples-light-token.
Report incorrect code
Copy
Ask AI
mod shared;
use light_client::rpc::Rpc;
use light_token_sdk::token::CreateTokenAccount;
use shared::SplMintContext;
use solana_sdk::{signature::Keypair, signer::Signer};
#[tokio::test(flavor = "multi_thread")]
async fn create_token_account() {
// Setup creates mint
// You can use light, spl, t22 mints to create a light token account.
let SplMintContext {
mut rpc,
payer,
mint,
} = shared::setup_spl_mint_context().await;
let account = Keypair::new();
let create_account_ix = CreateTokenAccount::new(
payer.pubkey(),
account.pubkey(),
mint,
payer.pubkey(),
)
.instruction()
.unwrap();
rpc.create_and_send_transaction(&[create_account_ix], &payer.pubkey(), &[&payer, &account])
.await
.unwrap();
let account_data = rpc.get_account(account.pubkey()).await.unwrap();
assert!(account_data.is_some());
}
1
Configure Rent
Report incorrect code
Copy
Ask AI
use light_token_sdk::token::CompressibleParamsCpi;
let compressible = CompressibleParamsCpi::new_ata(
compressible_config.clone(),
rent_sponsor.clone(),
system_program.clone(),
);
| Protocol PDA that stores account rent config. | |
| Light token program PDA that pays rent exemption at creation and claims rent when account compresses. | |
| Solana System Program to create the on-chain account. |
2
Build Account Infos and CPI
- invoke (External signer)
- invoke_signed (PDA is signer)
Report incorrect code
Copy
Ask AI
use light_token_sdk::token::CreateTokenAccountCpi;
CreateTokenAccountCpi {
payer: payer.clone(),
account: account.clone(),
mint: mint.clone(),
owner: data.owner,
compressible: Some(compressible_params),
}
.invoke()?;
| Payer | signer, mutable |
|
| light-token Account | signer*, mutable |
|
| Mint | - | The SPL or light-mint token mint. |
| Owner | Pubkey | The owner of the token account. Controls transfers and other operations. |
Report incorrect code
Copy
Ask AI
use light_token_sdk::token::CreateTokenAccountCpi;
let account_cpi = CreateTokenAccountCpi {
payer: payer.clone(),
account: account.clone(),
mint: mint.clone(),
owner: data.owner,
compressible: Some(compressible_params),
};
let signer_seeds: &[&[u8]] = &[TOKEN_ACCOUNT_SEED, &[bump]];
account_cpi.invoke_signed(&[signer_seeds])?;
Full Code Example
View Source Code or full examples with tests: examples-light-token.
- Anchor
- Native
Report incorrect code
Copy
Ask AI
#![allow(unexpected_cfgs)]
use anchor_lang::prelude::*;
use light_token_sdk::token::{CompressibleParamsCpi, CreateTokenAccountCpi};
declare_id!("4fi27siKEvKXJYN5WCzWuHdAw1rLed6Tprv9ZARv3Gxu");
#[program]
pub mod light_token_anchor_create_token_account {
use super::*;
pub fn create_token_account<'info>(
ctx: Context<'_, '_, '_, 'info, CreateTokenAccountAccounts<'info>>,
owner: Pubkey,
) -> Result<()> {
let compressible_params = CompressibleParamsCpi::new(
ctx.accounts.compressible_config.to_account_info(),
ctx.accounts.rent_sponsor.to_account_info(),
ctx.accounts.system_program.to_account_info(),
);
CreateTokenAccountCpi {
payer: ctx.accounts.payer.to_account_info(),
account: ctx.accounts.account.to_account_info(),
mint: ctx.accounts.mint.to_account_info(),
owner,
compressible: Some(compressible_params),
}
.invoke()?;
Ok(())
}
}
#[derive(Accounts)]
pub struct CreateTokenAccountAccounts<'info> {
#[account(mut)]
pub payer: Signer<'info>,
/// CHECK: Validated by light-token CPI
#[account(mut)]
pub account: Signer<'info>,
/// CHECK: Validated by light-token CPI
pub mint: AccountInfo<'info>,
/// CHECK: Validated by light-token CPI
pub compressible_config: AccountInfo<'info>,
pub system_program: Program<'info, System>,
/// CHECK: Validated by light-token CPI
#[account(mut)]
pub rent_sponsor: AccountInfo<'info>,
}
Report incorrect code
Copy
Ask AI
use super::authority_seeds;
use light_token_sdk::token::{CompressibleParamsCpi, CreateTokenAccountCpi};
use solana_program::{
account_info::AccountInfo, entrypoint::ProgramResult,
program_error::ProgramError, pubkey::Pubkey,
};
pub fn create_token_account_invoke(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
let [payer, account, mint, compressible_config, system_program, rent_sponsor] = accounts
else {
return Err(ProgramError::NotEnoughAccountKeys);
};
if data.len() < 32 {
return Err(ProgramError::InvalidInstructionData);
}
let owner = Pubkey::try_from(&data[..32]).map_err(|_| ProgramError::InvalidInstructionData)?;
let compressible_params = CompressibleParamsCpi::new(
compressible_config.clone(),
rent_sponsor.clone(),
system_program.clone(),
);
CreateTokenAccountCpi {
payer: payer.clone(),
account: account.clone(),
mint: mint.clone(),
owner,
compressible: Some(compressible_params),
}
.invoke()
}
pub fn create_token_account_invoke_signed(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
let [payer, account, mint, compressible_config, system_program, rent_sponsor] = accounts
else {
return Err(ProgramError::NotEnoughAccountKeys);
};
if data.len() < 33 {
return Err(ProgramError::InvalidInstructionData);
}
let owner = Pubkey::try_from(&data[..32]).map_err(|_| ProgramError::InvalidInstructionData)?;
let bump = data[32];
let signer_seeds = authority_seeds!(bump);
let compressible_params = CompressibleParamsCpi::new(
compressible_config.clone(),
rent_sponsor.clone(),
system_program.clone(),
);
CreateTokenAccountCpi {
payer: payer.clone(),
account: account.clone(),
mint: mint.clone(),
owner,
compressible: Some(compressible_params),
}
.invoke_signed(&[signer_seeds])
}