> ## Documentation Index
> Fetch the complete documentation index at: https://www.zkcompression.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Pinocchio Programs

> Build high-performance DeFi programs with rent-free accounts using Pinocchio

The Light-SDK sponsors rent-exemption for your PDAs, token accounts, and mints. Your program logic stays the same.

|                       | Before | After    |
| --------------------- | ------ | -------- |
| Rent (avg. DeFi pool) | \~\$2  | \~\$0.02 |

## What Changes

| Area               | Change                                                                                  |
| ------------------ | --------------------------------------------------------------------------------------- |
| State struct       | Add `compression_info: CompressionInfo` field, derive `LightPinocchioAccount`           |
| Program enum       | Derive `LightProgramPinocchio` to generate compress/decompress handlers                 |
| Entrypoint         | Route generated discriminators alongside your custom ones                               |
| Init handler       | Replace `spl_token` CPIs with `light_token_pinocchio` CPIs to create rent-free accounts |
| Other instructions | No changes                                                                              |

If you use Anchor instead of Pinocchio, see [Program Integration](./programs).

***

<Accordion title="Agent skill">
  Use the [light-sdk](https://github.com/Lightprotocol/skills/tree/main/skills/light-sdk) agent skill to build rent-free DeFi programs:

  ```
  npx skills add Lightprotocol/skills
  ```

  For orchestration, install the [general skill](https://zkcompression.com/skill.md):

  ```bash theme={null}
  npx skills add https://zkcompression.com
  ```
</Accordion>

<Callout type="info">
  Complete pinocchio Swap reference implementation: [pinocchio-swap](https://github.com/Lightprotocol/examples-light-token/tree/simplify-trait/pinocchio/swap)
</Callout>

<Tabs>
  <Tab title="Guide">
    ## Step 1: Dependencies

    ```toml theme={null}
    [dependencies]
    light-account-pinocchio = { version = "0.23.0", features = ["token", "std"] }
    light-token-pinocchio = "0.23.0"

    pinocchio = "0.9"
    pinocchio-pubkey = { version = "0.3", features = ["const"] }
    pinocchio-system = "0.3"
    borsh = { version = "0.10.4", default-features = false }
    bytemuck = { version = "1.21", features = ["derive"] }
    ```

    ## Step 2: State Struct

    Add `compression_info` field and derive `LightPinocchioAccount`:

    ```rust theme={null}
    use borsh::{BorshDeserialize, BorshSerialize};
    use light_account_pinocchio::{CompressionInfo, LightPinocchioAccount};

    #[derive(
        Default, Debug, Copy, Clone, PartialEq,
        BorshSerialize, BorshDeserialize,
        LightPinocchioAccount,
        bytemuck::Pod, bytemuck::Zeroable,
    )]
    #[repr(C)]
    pub struct PoolState {
        pub compression_info: CompressionInfo,

        // Your regular state...
        pub fee_bps: u16,
    }
    ```

    ## Step 3: Program Enum

    Declare your account types with their seed schemas:

    ```rust theme={null}
    use light_account_pinocchio::{
        derive_light_cpi_signer, pubkey_array, CpiSigner, LightProgramPinocchio,
    };
    use pinocchio::pubkey::Pubkey;

    pub const ID: Pubkey = pubkey_array!("YourProgram11111111111111111111111111111111");
    pub const LIGHT_CPI_SIGNER: CpiSigner =
        derive_light_cpi_signer!("YourProgram11111111111111111111111111111111");

    #[derive(LightProgramPinocchio)]
    pub enum ProgramAccounts {
        #[light_account(pda::seeds = [POOL_SEED, ctx.mint_a, ctx.mint_b], pda::zero_copy)]
        PoolState(PoolState),

        #[light_account(token::seeds = [POOL_VAULT_SEED, ctx.pool, ctx.mint], token::owner_seeds = [POOL_AUTHORITY_SEED])]
        Vault,

        #[light_account(associated_token)]
        UserToken,
    }
    ```

    This auto-generates 4 instructions, discriminators, and the `LightAccountVariant` enum used by the client SDK.

    ## Step 4: Entrypoint

    Dispatch the generated handlers in your entrypoint

    ```rust theme={null}
    pinocchio::entrypoint!(process_instruction);

    pub fn process_instruction(
        _program_id: &Pubkey,
        accounts: &[AccountInfo],
        instruction_data: &[u8],
    ) -> Result<(), ProgramError> {
        if instruction_data.len() < 8 {
            return Err(ProgramError::InvalidInstructionData);
        }

        let (disc, data) = instruction_data.split_at(8);
        let disc: [u8; 8] = disc.try_into().unwrap();

        match disc {
            // your custom program logic...
            discriminators::INITIALIZE => process_initialize(accounts, data),
            discriminators::SWAP => process_swap(accounts, data),

            // add this:
            ProgramAccounts::INITIALIZE_COMPRESSION_CONFIG => {
                ProgramAccounts::process_initialize_config(accounts, data) // generated
            }
            ProgramAccounts::UPDATE_COMPRESSION_CONFIG => {
                ProgramAccounts::process_update_config(accounts, data)
            }
            ProgramAccounts::COMPRESS_ACCOUNTS_IDEMPOTENT => {
                ProgramAccounts::process_compress(accounts, data)
            }
            ProgramAccounts::DECOMPRESS_ACCOUNTS_IDEMPOTENT => {
                ProgramAccounts::process_decompress(accounts, data)
            }
            _ => Err(ProgramError::InvalidInstructionData),
        }
    }
    ```

    ## Step 5: Init Handler

    Update your init instruction. Use `light_token_pinocchio` CPI builders to create rent-free token accounts.

    <Tabs>
      <Tab title="Create Token Account">
        ```rust theme={null}
        use light_account_pinocchio::CreateTokenAccountCpi;

        CreateTokenAccountCpi {
            payer: ctx.payer,
            account: vault,
            mint,
            owner: *pool_authority.key(),
        }
        .rent_free(
            ctx.light_token_config,
            ctx.light_token_rent_sponsor,
            ctx.system_program,
            &crate::ID,
        )
        .invoke_signed(&[
            POOL_VAULT_SEED,
            pool_key.as_ref(),
            mint_key.as_ref(),
            &[bump],
        ])?;
        ```
      </Tab>

      <Tab title="Create Mint">
        ```rust theme={null}
        use light_account_pinocchio::{CreateMints, CreateMintsStaticAccounts, SingleMintParams};

        let sdk_mints: [SingleMintParams<'_>; 2] = [
            SingleMintParams {
                decimals: 9,
                mint_authority: authority_key,
                mint_bump: None,
                freeze_authority: None,
                mint_seed_pubkey: mint_signer_a_key,
                authority_seeds: None,
                mint_signer_seeds: Some(mint_signer_a_seeds),
                token_metadata: None,
            },
            // ...
        ];

        CreateMints {
            mints: &sdk_mints,
            proof_data: &params.create_accounts_proof,
            mint_seed_accounts: ctx.mint_signers,
            mint_accounts: ctx.mints,
            static_accounts: CreateMintsStaticAccounts {
                fee_payer: ctx.payer,
                compressible_config: ctx.light_token_config,
                rent_sponsor: ctx.light_token_rent_sponsor,
                cpi_authority: ctx.cpi_authority,
            },
            cpi_context_offset: 1,
        }
        .invoke(&cpi_accounts)?;
        ```
      </Tab>
    </Tabs>

    <Accordion title="Full Initialize Processor">
      ```rust theme={null}
      use light_account_pinocchio::{
          prepare_compressed_account_on_init, CompressedCpiContext, CpiAccounts, CpiAccountsConfig,
          CpiContextWriteAccounts, CreateMints, CreateMintsStaticAccounts, CreateTokenAccountCpi,
          InstructionDataInvokeCpiWithAccountInfo, InvokeLightSystemProgram, LightAccount, LightConfig,
          SingleMintParams,
      };
      use pinocchio::sysvars::{clock::Clock, Sysvar};

      pub fn process(
          ctx: &InitializeAccounts<'_>,
          params: &InitializeParams,
          remaining_accounts: &[AccountInfo],
      ) -> Result<(), LightSdkTypesError> {
          // 1. Build CPI accounts
          let config = CpiAccountsConfig::new_with_cpi_context(crate::LIGHT_CPI_SIGNER);
          let cpi_accounts = CpiAccounts::new_with_config(
              ctx.payer,
              &remaining_accounts[params.create_accounts_proof.system_accounts_offset as usize..],
              config,
          );

          // 2. Get address tree info + config
          let address_tree_info = &params.create_accounts_proof.address_tree_info;
          let address_tree_pubkey = address_tree_info.get_tree_pubkey(&cpi_accounts)?;
          let light_config = LightConfig::load_checked(ctx.compressible_config, &crate::ID)?;
          let current_slot = Clock::get()?.slot;

          // 3. Create pool PDA (write to CPI context)
          {
              let cpi_context = CompressedCpiContext::first();
              let mut new_address_params = Vec::with_capacity(1);
              let mut account_infos = Vec::with_capacity(1);
              let pool_key = *ctx.pool.key();

              prepare_compressed_account_on_init(
                  &pool_key, &address_tree_pubkey, address_tree_info,
                  params.create_accounts_proof.output_state_tree_index,
                  0, &crate::ID,
                  &mut new_address_params, &mut account_infos,
              )?;

              // Initialize pool state (zero-copy)
              {
                  let mut data = ctx.pool.try_borrow_mut_data()?;
                  let pool_state: &mut PoolState = bytemuck::from_bytes_mut(
                      &mut data[8..8 + core::mem::size_of::<PoolState>()]
                  );
                  pool_state.set_decompressed(&light_config, current_slot);
                  pool_state.token_a_mint = *ctx.mint_a().key();
                  pool_state.token_b_mint = *ctx.mint_b().key();
                  // ... remaining fields
              }

              // Write to CPI context
              let instruction_data = InstructionDataInvokeCpiWithAccountInfo {
                  mode: 1,
                  bump: crate::LIGHT_CPI_SIGNER.bump,
                  invoking_program_id: crate::LIGHT_CPI_SIGNER.program_id.into(),
                  proof: params.create_accounts_proof.proof.0,
                  new_address_params,
                  account_infos,
                  // ...
              };
              instruction_data.invoke_write_to_cpi_context_first(
                  CpiContextWriteAccounts {
                      fee_payer: cpi_accounts.fee_payer(),
                      authority: cpi_accounts.authority()?,
                      cpi_context: cpi_accounts.cpi_context()?,
                      cpi_signer: crate::LIGHT_CPI_SIGNER,
                  }
              )?;
          }

          // 4. Create mints
          CreateMints { /* ... */ }.invoke(&cpi_accounts)?;

          // 5. Create vaults (rent-free)
          CreateTokenAccountCpi { /* ... */ }.rent_free(/* ... */).invoke_signed(/* ... */)?;

          Ok(())
      }
      ```
    </Accordion>
  </Tab>

  <Tab title="AI Prompt">
    <Prompt description="Add rent-free accounts to a Pinocchio DeFi program" actions={["copy", "cursor"]}>
      {`---
            description: Add rent-free accounts to a Pinocchio DeFi program
            allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression
            ---

            ## Add rent-free accounts to a Pinocchio DeFi program

            Context:
            - Guide: https://zkcompression.com/light-token/defi/programs-pinocchio
            - Skills and resources index: https://zkcompression.com/skill.md
            - Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/light-sdk
            - Crates: light-account-pinocchio (features: token, std), light-token-pinocchio, pinocchio
            - Swap reference: https://github.com/Lightprotocol/examples-light-token/tree/simplify-trait/pinocchio/swap

            Key macros/APIs: LightPinocchioAccount, LightProgramPinocchio, CreateTokenAccountCpi, derive_light_cpi_signer!

            ### 1. Index project
            - Grep \`pinocchio|entrypoint!|ProgramError|AccountInfo|process_instruction\` across src/
            - Glob \`**/*.rs\` and \`**/Cargo.toml\` for project structure
            - Identify: existing program module, account structs, PDA seeds, token accounts, init instructions
            - Read Cargo.toml — note existing dependencies and framework version
            - Task subagent (Grep/Read/WebFetch) if project has multiple crates to scan in parallel

            ### 2. Read references
            - WebFetch the guide above
            - WebFetch skill.md — check for a dedicated skill and resources matching this task
            - TaskCreate one todo per phase below to track progress

            ### 3. Clarify intention
            - AskUserQuestion: what is the goal? (new program from scratch, migrate existing program to rent-free, add rent-free accounts to specific instructions)
            - AskUserQuestion: which account types need to be rent-free? (PDAs, token accounts, ATAs, mints)
            - Summarize findings and wait for user confirmation before implementing

            ### 4. Create plan
            - Based on steps 1–3, draft an implementation plan
            - Follow the guide's step order: Dependencies → State Struct → Program Enum → Entrypoint → Init Handler
            - Identify which existing structs need changes (CompressionInfo field, LightPinocchioAccount derive, etc.)
            - If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion)
            - Present the plan to the user for approval before proceeding

            ### 5. Implement
            - Add deps if missing: Bash \`cargo add light-account-pinocchio@0.23 --features token,std\` and \`cargo add light-token-pinocchio@0.23\` and \`cargo add pinocchio@0.9\`
            - Follow the guide and the approved plan
            - Write/Edit to create or modify files
            - TaskUpdate to mark each step done

            ### 6. Verify
            - Bash \`cargo build-sbf\`
            - Bash \`cargo test-sbf\` if tests exist
            - TaskUpdate to mark complete

            ### Tools
            - mcp__zkcompression__SearchLightProtocol("<query>") for API details
            - mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "<q>") for architecture
            - Task subagent with Grep/Read/WebFetch for parallel lookups
            - TaskList to check remaining work`}
    </Prompt>

    ```text theme={null}
    ---
    description: Add rent-free accounts to a Pinocchio DeFi program
    allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression
    ---

    ## Add rent-free accounts to a Pinocchio DeFi program

    Context:
    - Guide: https://zkcompression.com/light-token/defi/programs-pinocchio
    - Skills and resources index: https://zkcompression.com/skill.md
    - Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/light-sdk
    - Crates: light-account-pinocchio (features: token, std), light-token-pinocchio, pinocchio
    - Swap reference: https://github.com/Lightprotocol/examples-light-token/tree/simplify-trait/pinocchio/swap

    Key macros/APIs: LightPinocchioAccount, LightProgramPinocchio, CreateTokenAccountCpi, derive_light_cpi_signer!

    ### 1. Index project
    - Grep `pinocchio|entrypoint!|ProgramError|AccountInfo|process_instruction` across src/
    - Glob `**/*.rs` and `**/Cargo.toml` for project structure
    - Identify: existing program module, account structs, PDA seeds, token accounts, init instructions
    - Read Cargo.toml — note existing dependencies and framework version
    - Task subagent (Grep/Read/WebFetch) if project has multiple crates to scan in parallel

    ### 2. Read references
    - WebFetch the guide above
    - WebFetch skill.md — check for a dedicated skill and resources matching this task
    - TaskCreate one todo per phase below to track progress

    ### 3. Clarify intention
    - AskUserQuestion: what is the goal? (new program from scratch, migrate existing program to rent-free, add rent-free accounts to specific instructions)
    - AskUserQuestion: which account types need to be rent-free? (PDAs, token accounts, ATAs, mints)
    - Summarize findings and wait for user confirmation before implementing

    ### 4. Create plan
    - Based on steps 1–3, draft an implementation plan
    - Follow the guide's step order: Dependencies → State Struct → Program Enum → Entrypoint → Init Handler
    - Identify which existing structs need changes (CompressionInfo field, LightPinocchioAccount derive, etc.)
    - If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion)
    - Present the plan to the user for approval before proceeding

    ### 5. Implement
    - Add deps if missing: Bash `cargo add light-account-pinocchio@0.23 --features token,std` and `cargo add light-token-pinocchio@0.23` and `cargo add pinocchio@0.9`
    - Follow the guide and the approved plan
    - Write/Edit to create or modify files
    - TaskUpdate to mark each step done

    ### 6. Verify
    - Bash `cargo build-sbf`
    - Bash `cargo test-sbf` if tests exist
    - TaskUpdate to mark complete

    ### Tools
    - mcp__zkcompression__SearchLightProtocol("<query>") for API details
    - mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "<q>") for architecture
    - Task subagent with Grep/Read/WebFetch for parallel lookups
    - TaskList to check remaining work
    ```
  </Tab>
</Tabs>

***

## Client SDK

Implement `LightProgramInterface` so clients can detect cold accounts and build load instructions.

<Accordion title="Example: LightProgramInterface Implementation">
  ```rust theme={null}
  use light_client::interface::{
      AccountInterface, AccountSpec, ColdContext, LightProgramInterface, PdaSpec,
  };
  use light_account::token::Token;
  use pinocchio_swap::{LightAccountVariant, PoolState, PoolStateSeeds, VaultSeeds};

  /// Flat SDK struct. All fields populated at construction from pool state data.
  pub struct SwapSdk {
      pub pool_state_pubkey: Pubkey,
      pub token_a_mint: Pubkey,
      pub token_b_mint: Pubkey,
      pub token_a_vault: Pubkey,
      pub token_b_vault: Pubkey,
      pub pool_authority: Pubkey,
  }

  impl SwapSdk {
      pub fn new(pool_state_pubkey: Pubkey, pool_data: &[u8]) -> Result<Self, SwapSdkError> {
          let pool = PoolState::deserialize(&mut &pool_data[8..])?;
          // ... derive addresses from pool state
          Ok(Self { pool_state_pubkey, /* ... */ })
      }
  }

  impl LightProgramInterface for SwapSdk {
      type Variant = LightAccountVariant;
      type Instruction = SwapInstruction;

      fn program_id() -> Pubkey { PROGRAM_ID }

      fn instruction_accounts(&self, ix: &Self::Instruction) -> Vec<Pubkey> {
          match ix {
              SwapInstruction::Swap => vec![
                  self.pool_state_pubkey,
                  self.token_a_vault,
                  self.token_b_vault,
                  self.token_a_mint,
                  self.token_b_mint,
              ],
              // ...
          }
      }

      fn load_specs(
          &self,
          cold_accounts: &[AccountInterface],
      ) -> Result<Vec<AccountSpec<Self::Variant>>, Box<dyn std::error::Error>> {
          let mut specs = Vec::new();
          for account in cold_accounts {
              if account.key == self.pool_state_pubkey {
                  let pool = PoolState::deserialize(&mut &account.data()[8..])?;
                  let variant = LightAccountVariant::PoolState {
                      seeds: PoolStateSeeds { /* ... */ },
                      data: pool,
                  };
                  specs.push(AccountSpec::Pda(PdaSpec::new(account.clone(), variant, PROGRAM_ID)));
              } else if account.key == self.token_a_vault {
                  let token: Token = Token::deserialize(&mut &account.data()[..])?;
                  let variant = LightAccountVariant::Vault(TokenDataWithSeeds {
                      seeds: VaultSeeds { pool: /* ... */, mint: /* ... */ },
                      token_data: token,
                  });
                  specs.push(AccountSpec::Pda(PdaSpec::new(account.clone(), variant, PROGRAM_ID)));
              }
              // ... token_b_vault, mints
          }
          Ok(specs)
      }
  }
  ```
</Accordion>

| Resource                | Link                                                                                                            |
| ----------------------- | --------------------------------------------------------------------------------------------------------------- |
| Full SDK implementation | [sdk.rs](https://github.com/Lightprotocol/examples-light-token/blob/simplify-trait/pinocchio/swap/tests/sdk.rs) |

***

## Testing

<Accordion title="Example: Full Lifecycle Test">
  ```rust theme={null}
  use light_program_test::{LightProgramTest, Rpc};
  use light_client::interface::{
      create_load_instructions, get_create_accounts_proof,
      AccountSpec, CreateAccountsProofInput, LightProgramInterface,
  };


  #[tokio::test]
  async fn test_pool_lifecycle() {
      let mut rpc = LightProgramTest::new(config).await.unwrap();

      // 1. Initialize pool (rent-free: pool PDA, 2 mints, 2 vaults)
      let proof = get_create_accounts_proof(&rpc, &program_id, vec![
          CreateAccountsProofInput::pda(pool_state),
          CreateAccountsProofInput::mint(mint_a_signer),
          CreateAccountsProofInput::mint(mint_b_signer),
      ]).await.unwrap();

      rpc.create_and_send_transaction(&[init_ix], &payer.pubkey(), &[&payer, &authority])
          .await.unwrap();

      // 2. Swap (hot path)
      rpc.create_and_send_transaction(&[swap_ix], &user.pubkey(), &[&user])
          .await.unwrap();

      // 3. Trigger compression for the purpose of the test.
      const SLOTS_PER_EPOCH: u64 = 13500;
      rpc.warp_slot_forward(SLOTS_PER_EPOCH * 30).await.unwrap();

      // 4. Build SDK from pool state, fetch cold accounts
      let pool_iface = rpc.get_account_interface(&pool_state, None).await.unwrap().value.unwrap();
      assert!(pool_iface.is_cold());

      let sdk = SwapSdk::new(pool_state, pool_iface.data()).unwrap();
      let pubkeys = sdk.instruction_accounts(&SwapInstruction::Swap);
      let accounts = rpc.get_multiple_account_interfaces(pubkeys.iter().collect(), None)
          .await.unwrap().value;
      let cold: Vec<_> = accounts.into_iter().flatten().filter(|a| a.is_cold()).collect();

      // 5. Load cold accounts
      let mut specs = sdk.load_specs(&cold).unwrap();
      // Add user ATAs
      let ata_a = rpc.get_associated_token_account_interface(&user.pubkey(), &mint_a, None)
          .await.unwrap().value.unwrap();
      let ata_b = rpc.get_associated_token_account_interface(&user.pubkey(), &mint_b, None)
          .await.unwrap().value.unwrap();
      specs.push(AccountSpec::Ata(ata_a));
      specs.push(AccountSpec::Ata(ata_b));

      let load_ixs = create_load_instructions(&specs, payer.pubkey(), config_pda, &rpc)
          .await.unwrap();


      // 6. Load and Swap
      let mut all_ixs = load_ixs;
      all_ixs.push(swap_ix);
      rpc.create_and_send_transaction(&all_ixs, &user.pubkey(), &[&user])
          .await.unwrap();
  }
  ```
</Accordion>

| Resource  | Link                                                                                                                                   |
| --------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Full test | [test\_lifecycle.rs](https://github.com/Lightprotocol/examples-light-token/blob/simplify-trait/pinocchio/swap/tests/test_lifecycle.rs) |

***

## How it works

The SDK pays the rent-exemption cost. After extended inactivity, cold accounts auto-compress. Your program only ever
interacts with hot accounts. Clients can safely load cold accounts back into the
onchain Solana account space when needed via `create_load_instructions`.

Under the hood, clients use `AccountInterface` - a superset of Solana's
`Account` that unifies hot and cold state. See [Router Integration](./routers)
for details.

|                   | Hot (active) | Cold (inactive)   |
| ----------------- | ------------ | ----------------- |
| Storage           | On-chain     | Compressed        |
| Latency/CU        | No change    | +load instruction |
| Your program code | No change    | No change         |

## Existing programs

If you want to migrate your program to rent-free accounts and would like hands-on support, [join our tech Discord](https://discord.com/invite/7cJ8BhAXhu),
or [email us](mailto:support@lightprotocol.com).

## FAQ

<Accordion title="Do I have to manually handle compression/decompression?">
  No. `LightProgramPinocchio` generates the handlers. Simply add the generated handlers to your entrypoint, and update your init instruction.
</Accordion>

<Accordion title="How does it prevent re-init attacks?"> When creating an
account for the first time, the SDK provides a proof that the account doesn't
exist in the cold address space. The SVM already verifies this for the onchain
space. Both address spaces are checked before creation, preventing re-init
attacks, even if the account is currently cold. </Accordion>

<Accordion title="Who triggers compression?">
  Miners (Forester nodes) compress accounts that have been inactive for an extended period of time (when their virtual rent balance drops below threshold).
  In practice, having to load cold accounts should be rare. The common path (hot) has no extra overhead and does not increase CU or txn size.
</Accordion>

<Accordion title="How is the SDK able to sponsor rent exemption?">
  When accounts compress after extended inactivity, the on-chain rent-exemption is released back
  to the rent sponsor. This creates a revolving lifecycle: active "hot" accounts hold a
  rent-exempt lamports balance, inactive "cold" accounts release it back. The
  rent sponsor must be derived from the program owner. For all mint, ATA, and
  token accounts, the Light Token Program is the rent sponsor. For your own program-owned PDAs, the SDK derives a rent sponsor address automatically.
</Accordion>

<Accordion title="Do rent-free accounts increase CU?">
  **Hot path (e.g. swap, deposit, withdraw):** No. Active accounts do not add CU overhead to your instructions.

  **First time init + loading cold accounts:** Yes, adds up to 15k-400k CU,
  depending on number and type of accounts being initialized or loaded.
</Accordion>

***

<Callout type="info">
  Questions or need hands-on support? [Telegram](https://t.me/swen_light) | [email](mailto:support@lightprotocol.com) | [Discord](https://discord.com/invite/7cJ8BhAXhu)
</Callout>
