> ## Documentation Index
> Fetch the complete documentation index at: https://luminouslabs-cc5545c6-docs-main-reorder.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Transfer Checked

> Rust client guide to transfer Light Tokens with decimal validation. Includes step-by-step implementation and full code examples.

***

1. TransferChecked validates that the decimals parameter matches the mint's decimals.
2. Use for Light→Light transfers when you need decimal verification.
3. For transfers involving SPL or Token 2022 accounts, use [Transfer Interface](/light-token/cookbook/transfer-interface) instead.

<Accordion title="Agent skill">
  Install the [agent skill](https://zkcompression.com/skill.md):

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

  See the [AI tools guide](/ai-tools/guide) for dedicated skills.
</Accordion>

<Tabs>
  <Tab title="Rust Client">
    <Tabs>
      <Tab title="Guide">
        <Steps>
          <Step>
            ### Prerequisites

            <Accordion title="Dependencies">
              ```toml Cargo.toml theme={null}
              [dependencies]
              light-token = "0.4.0"
              light-client = { version = "0.19.0", features = ["v2"] }
              solana-sdk = "2"
              borsh = "0.10.4"
              tokio = { version = "1", features = ["full"] }
              ```
            </Accordion>

            <Accordion title="Developer Environment">
              <Tabs>
                <Tab title="In-Memory (LightProgramTest)">
                  Test with Lite-SVM (...)

                  ```bash theme={null}
                  # Initialize project
                  cargo init my-light-project
                  cd my-light-project

                  # Run tests
                  cargo test
                  ```

                  ```rust theme={null}
                  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());
                  }
                  ```
                </Tab>

                <Tab title="Localnet (LightClient)">
                  Connects to a local test validator.

                  <Tabs>
                    <Tab title="npm">
                      ```bash theme={null}
                      npm install -g @lightprotocol/zk-compression-cli@beta
                      ```
                    </Tab>

                    <Tab title="yarn">
                      ```bash theme={null}
                      yarn global add @lightprotocol/zk-compression-cli@beta
                      ```
                    </Tab>

                    <Tab title="pnpm">
                      ```bash theme={null}
                      pnpm add -g @lightprotocol/zk-compression-cli@beta
                      ```
                    </Tab>
                  </Tabs>

                  ```bash theme={null}
                  # Initialize project
                  cargo init my-light-project
                  cd my-light-project

                  # Start local test validator (in separate terminal)
                  light test-validator
                  ```

                  ```rust theme={null}
                  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(())
                  }
                  ```
                </Tab>

                <Tab title="Devnet (LightClient)">
                  Replace `<your-api-key>` with your actual API key. [Get your API key here](https://www.helius.dev/zk-compression).

                  ```rust theme={null}
                  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(())
                  }
                  ```
                </Tab>
              </Tabs>
            </Accordion>
          </Step>

          <Step>
            ### Transfer with Decimal Check

            <Info>
              Find the source code [here](https://github.com/Lightprotocol/light-protocol/blob/main/sdk-libs/token-sdk/src/instruction/transfer_checked.rs).
            </Info>

            <Tabs>
              <Tab title="Action">
                ```rust theme={null}
                use borsh::BorshDeserialize;
                use light_client::rpc::Rpc;
                use light_token_client::actions::{CreateAta, TransferChecked};
                use rust_client::{setup, SetupContext};
                use solana_sdk::{signature::Keypair, signer::Signer};

                #[tokio::main]
                async fn main() -> Result<(), Box<dyn std::error::Error>> {
                    let SetupContext {
                        mut rpc,
                        payer,
                        mint,
                        associated_token_account,
                        decimals,
                        ..
                    } = setup().await;

                    // Create recipient associated token account
                    let recipient = Keypair::new();
                    let (_signature, recipient_associated_token_account) = CreateAta {
                        mint,
                        owner: recipient.pubkey(),
                        idempotent: true,
                    }
                    .execute(&mut rpc, &payer)
                    .await?;

                    // TransferChecked validates decimals match the mint's decimals.
                    // Only use for Light->Light transfers.
                    // Use TransferInterface for all other transfers (Light, SPL or Token-2022).
                    let sig = TransferChecked {
                        source: associated_token_account,
                        mint,
                        destination: recipient_associated_token_account,
                        amount: 1000,
                        decimals,
                    }
                    .execute(&mut rpc, &payer, &payer)
                    .await?;

                    let data = rpc
                        .get_account(recipient_associated_token_account)
                        .await?
                        .ok_or("Account not found")?;
                    let token = light_token_interface::state::Token::deserialize(&mut &data.data[..])?;
                    println!("Balance: {} Tx: {sig}", token.amount);

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

              <Tab title="Instruction">
                ```rust theme={null}
                use borsh::BorshDeserialize;
                use light_client::rpc::Rpc;
                use light_token::instruction::{
                    get_associated_token_address, CreateAssociatedTokenAccount, TransferChecked,
                };
                use rust_client::{setup, SetupContext};
                use solana_sdk::{signature::Keypair, signer::Signer};

                #[tokio::main]
                async fn main() -> Result<(), Box<dyn std::error::Error>> {
                    // Setup creates mint and associated token account with tokens
                    let SetupContext {
                        mut rpc,
                        payer,
                        mint,
                        associated_token_account,
                        decimals,
                        ..
                    } = setup().await;

                    let transfer_amount = 400_000u64;

                    // Create recipient associated token account
                    let recipient = Keypair::new();
                    let recipient_associated_token_account = get_associated_token_address(&recipient.pubkey(), &mint);

                    let create_associated_token_account_instruction = CreateAssociatedTokenAccount::new(payer.pubkey(), recipient.pubkey(), mint)
                        .instruction()?;

                    rpc.create_and_send_transaction(&[create_associated_token_account_instruction], &payer.pubkey(), &[&payer])
                        .await?;

                    // TransferChecked validates decimals match the mint's decimals
                    // Only use for Light->Light transfers.
                    // Use TransferInterface for all other transfers (Light, SPL or Token-2022).
                    let transfer_instruction = TransferChecked {
                        source: associated_token_account,
                        mint,
                        destination: recipient_associated_token_account,
                        amount: transfer_amount,
                        decimals,
                        authority: payer.pubkey(),
                        max_top_up: None,
                        fee_payer: None,
                    }
                    .instruction()?;

                    let sig = rpc
                        .create_and_send_transaction(&[transfer_instruction], &payer.pubkey(), &[&payer])
                        .await?;

                    let data = rpc
                        .get_account(recipient_associated_token_account)
                        .await?
                        .ok_or("Account not found")?;
                    let token = light_token_interface::state::Token::deserialize(&mut &data.data[..])?;
                    println!("Balance: {} Tx: {sig}", token.amount);

                    Ok(())
                }
                ```
              </Tab>
            </Tabs>
          </Step>
        </Steps>
      </Tab>

      <Tab title="AI Prompt">
        <Prompt description="Transfer tokens with decimal validation" actions={["copy", "cursor"]}>
          {`---
                    description: Transfer tokens with decimal validation
                    allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression
                    ---

                    ## Transfer tokens with decimal validation

                    Context:
                    - Guide: https://zkcompression.com/light-token/cookbook/transfer-checked
                    - Skills and resources index: https://zkcompression.com/skill.md
                    - Crates: light-token-client (actions), light-token (instructions), light-client (RPC)

                    TransferChecked validates that the decimals parameter matches the mint's decimals. Use for Light→Light transfers when you need decimal verification. For transfers involving SPL or Token 2022 accounts, use TransferInterface instead.

                    SPL equivalent: spl_token::instruction::transfer_checked → Light Token: TransferChecked

                    ### 1. Index project
                    - Grep \`light_token::|light_token_client::|solana_sdk|Keypair|async|TransferChecked|transfer_checked\` across src/
                    - Glob \`**/*.rs\` for project structure
                    - Identify: RPC setup, existing token ops, entry point for transfer checked
                    - Check Cargo.toml for existing light-* dependencies and solana-sdk version
                    - Task subagent (Grep/Read/WebFetch) if project has multiple crates to scan in parallel

                    ### 2. Read references
                    - WebFetch the guide above — follow the Rust Client tab
                    - 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 feature, migrate existing SPL code, add alongside existing)
                    - AskUserQuestion: does the project already have transfer operations to extend, or is this greenfield?
                    - AskUserQuestion: action-level API (high-level, fewer lines) or instruction-level API (low-level, full control)?
                    - Summarize findings and wait for user confirmation before implementing

                    ### 4. Create plan
                    - Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes
                    - Verify existing Rpc/signer setup is compatible with the cookbook prerequisites (light_client::rpc::Rpc, solana_sdk::signature::Keypair)
                    - 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-token-client light-token light-client --features light-client/v2\`
                    - Follow the cookbook guide and the approved plan
                    - Write/Edit to create or modify files
                    - TaskUpdate to mark each step done

                    ### 6. Verify
                    - Bash \`cargo check\`
                    - Bash \`cargo test\` 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: Transfer tokens with decimal validation
        allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression
        ---

        ## Transfer tokens with decimal validation

        Context:
        - Guide: https://zkcompression.com/light-token/cookbook/transfer-checked
        - Skills and resources index: https://zkcompression.com/skill.md
        - Crates: light-token-client (actions), light-token (instructions), light-client (RPC)

        TransferChecked validates that the decimals parameter matches the mint's decimals. Use for Light→Light transfers when you need decimal verification. For transfers involving SPL or Token 2022 accounts, use TransferInterface instead.

        SPL equivalent: spl_token::instruction::transfer_checked → Light Token: TransferChecked

        ### 1. Index project
        - Grep `light_token::|light_token_client::|solana_sdk|Keypair|async|TransferChecked|transfer_checked` across src/
        - Glob `**/*.rs` for project structure
        - Identify: RPC setup, existing token ops, entry point for transfer checked
        - Check Cargo.toml for existing light-* dependencies and solana-sdk version
        - Task subagent (Grep/Read/WebFetch) if project has multiple crates to scan in parallel

        ### 2. Read references
        - WebFetch the guide above — follow the Rust Client tab
        - 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 feature, migrate existing SPL code, add alongside existing)
        - AskUserQuestion: does the project already have transfer operations to extend, or is this greenfield?
        - AskUserQuestion: action-level API (high-level, fewer lines) or instruction-level API (low-level, full control)?
        - Summarize findings and wait for user confirmation before implementing

        ### 4. Create plan
        - Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes
        - Verify existing Rpc/signer setup is compatible with the cookbook prerequisites (light_client::rpc::Rpc, solana_sdk::signature::Keypair)
        - 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-token-client light-token light-client --features light-client/v2`
        - Follow the cookbook guide and the approved plan
        - Write/Edit to create or modify files
        - TaskUpdate to mark each step done

        ### 6. Verify
        - Bash `cargo check`
        - Bash `cargo test` 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>
  </Tab>

  <Tab title="Program">
    <Tabs>
      <Tab title="Guide">
        <Note>
          Find [a full code example at the end](#full-code-example).
        </Note>

        <Steps>
          <Step>
            ### Transfer Checked with CPI

            <Tabs>
              <Tab title="invoke (External signer)">
                ```rust theme={null}
                use light_token::instruction::TransferCheckedCpi;

                TransferCheckedCpi {
                    source: source.clone(),
                    mint: mint.clone(),
                    destination: destination.clone(),
                    amount,
                    decimals,
                    authority: authority.clone(),
                    system_program: system_program.clone(),
                    max_top_up: None,
                    fee_payer: None,
                }
                .invoke()?;
                ```
              </Tab>

              <Tab title="invoke_signed (PDA signer)">
                ```rust theme={null}
                use light_token::instruction::TransferCheckedCpi;

                let signer_seeds = authority_seeds!(bump);

                TransferCheckedCpi {
                    source: source.clone(),
                    mint: mint.clone(),
                    destination: destination.clone(),
                    amount,
                    decimals,
                    authority: authority.clone(),
                    system_program: system_program.clone(),
                    max_top_up: None,
                    fee_payer: None,
                }
                .invoke_signed(&[signer_seeds])?;
                ```
              </Tab>
            </Tabs>
          </Step>
        </Steps>

        # Full Code Example

        <Info>
          View the [source code](https://github.com/Lightprotocol/light-protocol/blob/main/sdk-libs/token-sdk/src/instruction/transfer_checked.rs) and [full example](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-instructions/transfer-checked) with shared test utilities.
        </Info>

        <CodeGroup>
          ```rust lib.rs theme={null}
          #![allow(unexpected_cfgs, deprecated)]

          use anchor_lang::prelude::*;
          use light_token::instruction::TransferCheckedCpi;

          declare_id!("HXmfewpozFdxhM8BayL9v5541gwoGMXTrUoip5KySs2f");

          #[program]
          pub mod light_token_anchor_transfer_checked {
              use super::*;

              pub fn transfer_checked(
                  ctx: Context<TransferCheckedAccounts>,
                  amount: u64,
                  decimals: u8,
              ) -> Result<()> {
                  TransferCheckedCpi {
                      source: ctx.accounts.source.to_account_info(),
                      mint: ctx.accounts.mint.to_account_info(),
                      destination: ctx.accounts.destination.to_account_info(),
                      amount,
                      decimals,
                      authority: ctx.accounts.authority.to_account_info(),
                      system_program: ctx.accounts.system_program.to_account_info(),
                      max_top_up: None,
                      fee_payer: None,
                  }
                  .invoke()?;
                  Ok(())
              }
          }

          #[derive(Accounts)]
          pub struct TransferCheckedAccounts<'info> {
              /// CHECK: Light token program for CPI
              pub light_token_program: AccountInfo<'info>,
              /// CHECK: Validated by light-token CPI
              #[account(mut)]
              pub source: AccountInfo<'info>,
              /// CHECK: Validated by light-token CPI
              pub mint: AccountInfo<'info>,
              /// CHECK: Validated by light-token CPI
              #[account(mut)]
              pub destination: AccountInfo<'info>,
              pub authority: Signer<'info>,
              pub system_program: Program<'info, System>,
          }
          ```

          ```rust test.rs theme={null}
          use anchor_lang::{InstructionData, ToAccountMetas};
          use light_program_test::Rpc;
          use light_token::instruction::LIGHT_TOKEN_PROGRAM_ID;
          use light_token_anchor_transfer_checked::{accounts, instruction::TransferChecked, ID};
          use anchor_lang::system_program;
          use solana_sdk::{instruction::Instruction, signature::Keypair, signer::Signer};
          use test_utils::{create_associated_token_account_for_owner, mint_tokens, setup_test_env};

          #[tokio::test]
          async fn test_transfer_checked() {
              let mut env = setup_test_env("light_token_anchor_transfer_checked", ID).await;
              mint_tokens(&mut env.rpc, &env.payer, env.mint_pda, env.associated_token_account, 1_000_000).await;

              // Create destination associated token account for recipient
              let recipient = Keypair::new();
              let dest_associated_token_account =
                  create_associated_token_account_for_owner(&mut env.rpc, &env.payer, &recipient.pubkey(), &env.mint_pda).await;

              // TransferChecked validates decimals match the mint's decimals.
              // Only use for Light->Light transfers.
              // Use TransferInterface for all other transfers (Light, SPL or Token-2022).
              let transfer_amount = 100_000u64;
              let decimals = 9u8;

              let ix = Instruction {
                  program_id: ID,
                  accounts: accounts::TransferCheckedAccounts {
                      light_token_program: LIGHT_TOKEN_PROGRAM_ID,
                      source: env.associated_token_account,
                      mint: env.mint_pda,
                      destination: dest_associated_token_account,
                      authority: env.payer.pubkey(),
                      system_program: system_program::ID,
                  }
                  .to_account_metas(Some(true)),
                  data: TransferChecked {
                      amount: transfer_amount,
                      decimals,
                  }
                  .data(),
              };

              let sig = env
                  .rpc
                  .create_and_send_transaction(&[ix], &env.payer.pubkey(), &[&env.payer])
                  .await
                  .unwrap();

              println!("Tx: {}", sig);
          }
          ```
        </CodeGroup>
      </Tab>

      <Tab title="AI Prompt">
        <Prompt description="Add transfer-checked CPI to an Anchor program" actions={["copy", "cursor"]}>
          {`---
                    description: Add transfer-checked CPI to an Anchor program
                    allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression
                    ---

                    ## Add transfer-checked CPI to an Anchor program

                    Context:
                    - Guide: https://zkcompression.com/light-token/cookbook/transfer-checked
                    - Skills and resources index: https://zkcompression.com/skill.md
                    - Crate: light-token (TransferCheckedCpi)
                    - Example: https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-instructions/transfer-checked

                    Key CPI struct: \`light_token::instruction::TransferCheckedCpi\`

                    ### 1. Index project
                    - Grep \`declare_id|#\[program\]|anchor_lang|Account<|Pubkey|invoke|transfer|decimals|amount\` across src/
                    - Glob \`**/*.rs\` and \`**/Cargo.toml\` for project structure
                    - Identify: program ID, existing instructions, account structs, token accounts
                    - 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 — review the Program tab CPI code samples
                    - 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? (add transfer-checked to existing program, new program from scratch, migrate from SPL transfer_checked)
                    - AskUserQuestion: should the authority be an external signer or a PDA? (determines invoke vs invoke_signed)
                    - Summarize findings and wait for user confirmation before implementing

                    ### 4. Create plan
                    - Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes
                    - Follow the guide's step order: Build TransferCheckedCpi struct → call .invoke() or .invoke_signed()
                    - 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-token anchor-lang@0.31\`
                    - Follow the guide and the approved plan
                    - Write/Edit to create or modify files
                    - TaskUpdate to mark each step done

                    ### 6. Verify
                    - Bash \`anchor build\`
                    - Bash \`anchor test\` 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 transfer-checked CPI to an Anchor program
        allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression
        ---

        ## Add transfer-checked CPI to an Anchor program

        Context:
        - Guide: https://zkcompression.com/light-token/cookbook/transfer-checked
        - Skills and resources index: https://zkcompression.com/skill.md
        - Crate: light-token (TransferCheckedCpi)
        - Example: https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-instructions/transfer-checked

        Key CPI struct: `light_token::instruction::TransferCheckedCpi`

        ### 1. Index project
        - Grep `declare_id|#\[program\]|anchor_lang|Account<|Pubkey|invoke|transfer|decimals|amount` across src/
        - Glob `**/*.rs` and `**/Cargo.toml` for project structure
        - Identify: program ID, existing instructions, account structs, token accounts
        - 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 — review the Program tab CPI code samples
        - 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? (add transfer-checked to existing program, new program from scratch, migrate from SPL transfer_checked)
        - AskUserQuestion: should the authority be an external signer or a PDA? (determines invoke vs invoke_signed)
        - Summarize findings and wait for user confirmation before implementing

        ### 4. Create plan
        - Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes
        - Follow the guide's step order: Build TransferCheckedCpi struct → call .invoke() or .invoke_signed()
        - 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-token anchor-lang@0.31`
        - Follow the guide and the approved plan
        - Write/Edit to create or modify files
        - TaskUpdate to mark each step done

        ### 6. Verify
        - Bash `anchor build`
        - Bash `anchor test` 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>
  </Tab>
</Tabs>

# Next Steps

{" "}

<Card title="Learn how to close Light Token accounts" icon="chevron-right" color="#0066ff" href="/light-token/cookbook/close-token-account" horizontal />
