Expand description
The base library to use Compressed Accounts in Solana on-chain Rust and Anchor programs. Compressed accounts do not require rent-exemption, which makes them suitable for:
- user owned accounts
- not for config accounts which are often read
- not pool accounts, since compressed accounts cannot be used concurrently
Compressed Accounts store state as account hashes in State Merkle trees. and unique addresses in Address Merkle trees. Validity proofs (zero-knowledge proofs) verify that compressed account state exists and new addresses do not exist yet.
- No rent exemption payment required.
- Constant 128-byte validity proof per transaction for one or multiple compressed accounts and addresses.
- Compressed account data is sent as instruction data when accessed.
- State and address trees are managed by the protocol.
For full program examples, see the Program Examples.
For detailed documentation, visit zkcompression.com.
For pinocchio solana program development see light-sdk-pinocchio.
For rust client development see light-client.
For rust program testing see light-program-test.
For local test validator with light system programs see Light CLI.
§Difference to Light-Accounts (Light-PDA)
Light-PDAs are Solana accounts with sponsored rent-exemption. There is no proof required for interactions with Light-PDAs which makes them suitable for Defi Usecases. Compressed PDAs don’t require rent-exemption, but a proof for interactions.
§Using Compressed Accounts in Solana Programs
InstructionCompressedAccountMeta- Compressed account metadata structs for instruction data.PackedAccounts- Abstraction to prepare accounts offchain for instructions with compressed accounts.ValidityProof- Proves that new addresses don’t exist yet, and compressed account state exists.
- Compressed Account in Program
LightAccount- Compressed account abstraction similar to anchor Account.derive_address- Create a compressed account address.LightDiscriminator- DeriveMacro to derive a compressed account discriminator.
CpiCpiAccounts- Prepare accounts to cpi the light system program.LightSystemProgramCpi- Prepare instruction data to cpi the light system program.InvokeLightSystemProgram::invoke- Invoke the light system program via cpi.
§Client Program Interaction Flow
├─ 𝐂𝐥𝐢𝐞𝐧𝐭
│ ├─ Get ValidityProof from RPC.
│ ├─ pack accounts with PackedAccounts into PackedAddressTreeInfo and PackedStateTreeInfo.
│ ├─ pack CompressedAccountMeta.
│ ├─ Build Instruction from PackedAccounts and CompressedAccountMetas.
│ └─ Send transaction.
│
└─ 𝐂𝐮𝐬𝐭𝐨𝐦 𝐏𝐫𝐨𝐠𝐫𝐚𝐦
├─ CpiAccounts parse accounts consistent with PackedAccounts.
├─ LightAccount instantiates from CompressedAccountMeta.
│
└─ 𝐋𝐢𝐠𝐡𝐭 𝐒𝐲𝐬𝐭𝐞𝐦 𝐏𝐫𝐨𝐠𝐫𝐚𝐦 𝐂𝐏𝐈
├─ Verify ValidityProof.
├─ Update State Merkle tree.
├─ Update Address Merkle tree.
└─ Complete atomic state transition.§Features
-
anchor- Derives AnchorSerialize, AnchorDeserialize instead of BorshSerialize, BorshDeserialize. -
v2- available on devnet, localnet, and light-program-test.
- Support for optimized v2 light system program instructions.
-
cpi-context- Enables CPI context operations for batched compressed account operations.- available on devnet, localnet, and light-program-test.
- Enables the use of one validity proof across multiple cpis from different programs in one instruction.
- For example spending compressed tokens (owned by the ctoken program) and updating a compressed pda (owned by a custom program) with one validity proof.
- An instruction should not use more than one validity proof.
- Requires the v2 feature.
§Example Solana program code to create a compressed account
use anchor_lang::{prelude::*, Discriminator};
use light_sdk::{
account::LightAccount,
address::v1::derive_address,
cpi::{v1::LightSystemProgramCpi, CpiAccounts, InvokeLightSystemProgram, LightCpiInstruction},
derive_light_cpi_signer,
instruction::{account_meta::CompressedAccountMeta, PackedAddressTreeInfo},
CpiSigner, LightDiscriminator, LightHasher, ValidityProof,
};
declare_id!("2tzfijPBGbrR5PboyFUFKzfEoLTwdDSHUjANCw929wyt");
pub const LIGHT_CPI_SIGNER: CpiSigner =
derive_light_cpi_signer!("2tzfijPBGbrR5PboyFUFKzfEoLTwdDSHUjANCw929wyt");
#[program]
pub mod counter {
use super::*;
pub fn create_compressed_account<'info>(
ctx: Context<'_, '_, '_, 'info, CreateCompressedAccount<'info>>,
proof: ValidityProof,
address_tree_info: PackedAddressTreeInfo,
output_tree_index: u8,
) -> Result<()> {
let light_cpi_accounts = CpiAccounts::new(
ctx.accounts.fee_payer.as_ref(),
ctx.remaining_accounts,
crate::LIGHT_CPI_SIGNER,
)?;
let (address, address_seed) = derive_address(
&[b"counter", ctx.accounts.fee_payer.key().as_ref()],
&address_tree_info.get_tree_pubkey(&light_cpi_accounts)?,
&crate::ID,
);
let new_address_params = address_tree_info
.into_new_address_params_packed(address_seed);
let mut my_compressed_account = LightAccount::<CounterAccount>::new_init(
&crate::ID,
Some(address),
output_tree_index,
);
my_compressed_account.owner = ctx.accounts.fee_payer.key();
LightSystemProgramCpi::new_cpi(crate::LIGHT_CPI_SIGNER, proof)
.with_light_account(my_compressed_account)?
.with_new_addresses(&[new_address_params])
.invoke(light_cpi_accounts)
}
}
#[derive(Accounts)]
pub struct CreateCompressedAccount<'info> {
#[account(mut)]
pub fee_payer: Signer<'info>,
}
#[derive(Clone, Debug, Default, LightDiscriminator)]
pub struct CounterAccount {
pub owner: Pubkey,
pub counter: u64
}Re-exports§
pub extern crate light_hasher;pub use account::sha::LightAccount;pub use proof::borsh_compat;pub use crate::cpi::LightCpiInstruction;pub use light_account_checks;
Modules§
- account
- Compressed account abstraction similar to anchor Account.
- address
- Functions to derive compressed account addresses.
- compressed_
account - constants
- cpi
- Utilities to invoke the light-system-program via cpi.
- error
- hasher
- instruction
- Utilities to build instructions for programs with compressed accounts.
- legacy
- Legacy types re-imported from programs which should be removed as soon as possible.
- proof
- sdk_
types - transfer
- Transfer compressed sol between compressed accounts.
- utils
Macros§
- derive_
light_ cpi_ signer - Derives a complete Light Protocol CPI configuration at runtime
- derive_
light_ cpi_ signer_ pda - Derives a Light Protocol CPI signer PDA at compile time
- derive_
light_ rent_ sponsor - Derives a complete Rent Sponsor configuration for a program at compile time.
- derive_
light_ rent_ sponsor_ pda - Derives a Rent Sponsor PDA for a program at compile time.
- find_
cpi_ signer_ macro
Structs§
- CpiSigner
- Configuration struct containing program ID, CPI signer, and bump for Light Protocol
Traits§
- Light
Discriminator - Packed
Address Tree Info Ext - Extension trait for PackedAddressTreeInfo SDK-specific methods. Since PackedAddressTreeInfo is defined in light-compressed-account, we use an extension trait to add methods that depend on SDK types.
- Pubkey
Trait
Derive Macros§
- Anchor
Discriminator - Derives a discriminator using SHA256(“account:{struct_name}”)[0..8].
- Light
Discriminator - Derives a discriminator using SHA256(“{struct_name}”)[0..8].
- Light
Hasher - Makes the annotated struct hashable by implementing the following traits:
- Light
Hasher Sha - SHA256 variant of the LightHasher derive macro.