> ## 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.

# Wrap & Unwrap SPL/Token 2022 <> Light Token

> Move tokens between SPL/Token 2022 token and Light Token accounts. Use to interact with applications that only support SPL/Token 2022.

***

* **Wrap**: Move tokens from SPL/Token 2022 account → Light Token ATA (hot balance)
* **Unwrap**: Move tokens from Light Token ATA (hot balance) → SPL/Token 2022 account

<Info>
  Find the source code:
  [wrap.ts](https://github.com/Lightprotocol/light-protocol/blob/main/js/compressed-token/src/v3/actions/wrap.ts)
  |
  [unwrap.ts](https://github.com/Lightprotocol/light-protocol/blob/main/js/compressed-token/src/v3/actions/unwrap.ts)
</Info>

<Accordion title="Agent skill">
  Install or view [dedicated agent skills](/ai-tools/overview#agent-skills).

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

  Install orchestrator agent skill or view [skill.md](https://www.zkcompression.com/skill.md):

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

<Tabs>
  <Tab title="TypeScript Client">
    <Tabs>
      <Tab title="Guide">
        <Tabs>
          <Tab title="Wrap">
            <Steps>
              <Step>
                ### Wrap SPL Tokens to Light Token ATA

                <Accordion title="Installation">
                  <Tabs>
                    <Tab title="npm">
                      Install packages in your working directory:

                      ```bash theme={null}
                      npm install @lightprotocol/stateless.js@^0.23.0 \
                                  @lightprotocol/compressed-token@^0.23.0
                      ```

                      Install the CLI globally:

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

                    <Tab title="yarn">
                      Install packages in your working directory:

                      ```bash theme={null}
                      yarn add @lightprotocol/stateless.js@^0.23.0 \
                               @lightprotocol/compressed-token@^0.23.0
                      ```

                      Install the CLI globally:

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

                    <Tab title="pnpm">
                      Install packages in your working directory:

                      ```bash theme={null}
                      pnpm add @lightprotocol/stateless.js@^0.23.0 \
                               @lightprotocol/compressed-token@^0.23.0
                      ```

                      Install the CLI globally:

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

                    <Tab title="SDK 2.0 (token-interface)">
                      Install packages in your working directory:

                      ```bash theme={null}
                      # npm
                      npm install @lightprotocol/stateless.js@^0.23.0 \
                                  @lightprotocol/token-interface@^0.1.2

                      # yarn
                      yarn add @lightprotocol/stateless.js@^0.23.0 \
                               @lightprotocol/token-interface@^0.1.2

                      # pnpm
                      pnpm add @lightprotocol/stateless.js@^0.23.0 \
                               @lightprotocol/token-interface@^0.1.2
                      ```

                      Install the CLI globally:

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

                <Tabs>
                  <Tab title="Localnet">
                    ```bash theme={null}
                    # start local test-validator in a separate terminal
                    light test-validator
                    ```

                    <Note>
                      In the code examples, use `createRpc()` without arguments for localnet.
                    </Note>
                  </Tab>

                  <Tab title="Devnet">
                    Get an API key from [Helius](https://helius.dev) and add to `.env`:

                    ```bash title=".env" theme={null}
                    API_KEY=<your-helius-api-key>
                    ```

                    <Note>
                      In the code examples, use `createRpc(RPC_URL)` with the devnet URL.
                    </Note>
                  </Tab>
                </Tabs>

                <Tabs>
                  <Tab title="Action">
                    ```typescript theme={null}
                    import "dotenv/config";
                    import { Keypair } from "@solana/web3.js";
                    import { createRpc } from "@lightprotocol/stateless.js";
                    import {
                        createMintInterface,
                        createAtaInterface,
                        getAssociatedTokenAddressInterface,
                    } from "@lightprotocol/compressed-token";
                    import { wrap } from "@lightprotocol/compressed-token/unified";
                    import {
                        TOKEN_PROGRAM_ID,
                        createAssociatedTokenAccount,
                        mintTo,
                    } from "@solana/spl-token";
                    import { homedir } from "os";
                    import { readFileSync } from "fs";

                    // devnet:
                    // const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`;
                    // const rpc = createRpc(RPC_URL);
                    // localnet:
                    const rpc = createRpc();

                    const payer = Keypair.fromSecretKey(
                        new Uint8Array(
                            JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8"))
                        )
                    );

                    (async function () {
                        // Setup: Create SPL mint and fund an SPL ATA
                        const { mint } = await createMintInterface(
                            rpc,
                            payer,
                            payer,
                            null,
                            9,
                            undefined,
                            undefined,
                            TOKEN_PROGRAM_ID
                        );
                        const splAta = await createAssociatedTokenAccount(
                            rpc,
                            payer,
                            mint,
                            payer.publicKey,
                            undefined,
                            TOKEN_PROGRAM_ID
                        );
                        await mintTo(rpc, payer, mint, splAta, payer, 1000);

                        // Create light-token ATA and wrap SPL tokens into it
                        await createAtaInterface(rpc, payer, mint, payer.publicKey);
                        const lightTokenAta = getAssociatedTokenAddressInterface(
                            mint,
                            payer.publicKey
                        );

                        const tx = await wrap(rpc, payer, splAta, lightTokenAta, payer, mint, BigInt(500));

                        console.log("Tx:", tx);
                    })();
                    ```
                  </Tab>

                  <Tab title="Instruction">
                    ```typescript theme={null}
                    import "dotenv/config";
                    import {
                        Keypair,
                        ComputeBudgetProgram,
                        Transaction,
                        sendAndConfirmTransaction,
                    } from "@solana/web3.js";
                    import { createRpc } from "@lightprotocol/stateless.js";
                    import {
                        createMintInterface,
                        createAtaInterface,
                        createWrapInstruction,
                        getAssociatedTokenAddressInterface,
                        getSplInterfaceInfos,
                    } from "@lightprotocol/compressed-token";
                    import {
                        TOKEN_PROGRAM_ID,
                        createAssociatedTokenAccount,
                        mintTo,
                    } from "@solana/spl-token";
                    import { homedir } from "os";
                    import { readFileSync } from "fs";

                    // devnet:
                    // const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`;
                    // const rpc = createRpc(RPC_URL);
                    // localnet:
                    const rpc = createRpc();

                    const payer = Keypair.fromSecretKey(
                        new Uint8Array(
                            JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8"))
                        )
                    );

                    (async function () {
                        // Setup: Create SPL mint and fund an SPL ATA
                        const { mint } = await createMintInterface(
                            rpc,
                            payer,
                            payer,
                            null,
                            9,
                            undefined,
                            undefined,
                            TOKEN_PROGRAM_ID
                        );
                        const splAta = await createAssociatedTokenAccount(
                            rpc,
                            payer,
                            mint,
                            payer.publicKey,
                            undefined,
                            TOKEN_PROGRAM_ID
                        );
                        await mintTo(rpc, payer, mint, splAta, payer, 1000);

                        // Create wrap instruction
                        await createAtaInterface(rpc, payer, mint, payer.publicKey);
                        const lightTokenAta = getAssociatedTokenAddressInterface(
                            mint,
                            payer.publicKey
                        );

                        const splInterfaceInfos = await getSplInterfaceInfos(rpc, mint);
                        const splInterfaceInfo = splInterfaceInfos.find(
                            (info) => info.isInitialized
                        );

                        if (!splInterfaceInfo) throw new Error("No SPL interface found");

                        const ix = createWrapInstruction(
                            splAta,
                            lightTokenAta,
                            payer.publicKey,
                            mint,
                            500,
                            splInterfaceInfo,
                            9,
                            payer.publicKey
                        );

                        const tx = new Transaction().add(
                            ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 }),
                            ix
                        );
                        const signature = await sendAndConfirmTransaction(rpc, tx, [payer]);

                        console.log("Tx:", signature);
                    })();
                    ```
                  </Tab>

                  <Tab title="SDK 2.0 (token-interface)">
                    ```typescript theme={null}
                    import { ComputeBudgetProgram, Keypair, Transaction, sendAndConfirmTransaction } from "@solana/web3.js";
                    import { createRpc } from "@lightprotocol/stateless.js";
                    import {
                      createAtaInstruction,
                      createWrapInstruction,
                      getAtaAddress,
                      getSplInterfaces,
                    } from "@lightprotocol/token-interface";

                    const rpc = createRpc();
                    const payer = Keypair.fromSecretKey(/* ... */);

                    const mint = /* existing SPL/Token-2022 mint */;
                    const splAta = /* existing SPL ATA */;
                    const lightTokenAta = getAtaAddress({ mint, owner: payer.publicKey });

                    const createAtaIx = createAtaInstruction({
                      payer: payer.publicKey,
                      owner: payer.publicKey,
                      mint,
                    });

                    const splInterfaces = await getSplInterfaces(rpc, mint);
                    const splInterface =
                      splInterfaces.find((info) => info.isInitialized) ?? splInterfaces[0];
                    if (!splInterface) throw new Error("No SPL interface found");

                    const wrapIx = createWrapInstruction({
                      source: splAta,
                      destination: lightTokenAta,
                      owner: payer.publicKey,
                      mint,
                      amount: 500n,
                      splInterface,
                      decimals: 9,
                      payer: payer.publicKey,
                    });

                    const tx = new Transaction().add(
                      ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 }),
                      createAtaIx,
                      wrapIx
                    );
                    const signature = await sendAndConfirmTransaction(rpc, tx, [payer]);
                    console.log("Tx:", signature);
                    ```
                  </Tab>
                </Tabs>
              </Step>
            </Steps>
          </Tab>

          <Tab title="Unwrap">
            <Steps>
              <Step>
                ### Unwrap Light Tokens to SPL Account

                <Tabs>
                  <Tab title="Action">
                    ```typescript theme={null}
                    import "dotenv/config";
                    import { Keypair } from "@solana/web3.js";
                    import { createRpc } from "@lightprotocol/stateless.js";
                    import {
                        createMintInterface,
                        createAtaInterface,
                        getAssociatedTokenAddressInterface,
                    } from "@lightprotocol/compressed-token";
                    import { wrap, unwrap } from "@lightprotocol/compressed-token/unified";
                    import {
                        TOKEN_PROGRAM_ID,
                        createAssociatedTokenAccount,
                        mintTo,
                    } from "@solana/spl-token";
                    import { homedir } from "os";
                    import { readFileSync } from "fs";

                    // devnet:
                    // const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`;
                    // const rpc = createRpc(RPC_URL);
                    // localnet:
                    const rpc = createRpc();

                    const payer = Keypair.fromSecretKey(
                        new Uint8Array(
                            JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8"))
                        )
                    );

                    (async function () {
                        // Setup: Create SPL mint, fund SPL ATA, wrap into Light ATA
                        const { mint } = await createMintInterface(
                            rpc,
                            payer,
                            payer,
                            null,
                            9,
                            undefined,
                            undefined,
                            TOKEN_PROGRAM_ID
                        );
                        const splAta = await createAssociatedTokenAccount(
                            rpc,
                            payer,
                            mint,
                            payer.publicKey,
                            undefined,
                            TOKEN_PROGRAM_ID
                        );
                        await mintTo(rpc, payer, mint, splAta, payer, 1000);

                        await createAtaInterface(rpc, payer, mint, payer.publicKey);
                        const lightTokenAta = getAssociatedTokenAddressInterface(
                            mint,
                            payer.publicKey
                        );
                        await wrap(rpc, payer, splAta, lightTokenAta, payer, mint, BigInt(1000));

                        // Unwrap: move tokens back from light-token to SPL ATA
                        const tx = await unwrap(rpc, payer, splAta, payer, mint, 500);

                        console.log("Tx:", tx);
                    })();
                    ```
                  </Tab>

                  <Tab title="Instruction">
                    ```typescript theme={null}
                    import "dotenv/config";
                    import {
                        Keypair,
                        Transaction,
                        sendAndConfirmTransaction,
                    } from "@solana/web3.js";
                    import { createRpc } from "@lightprotocol/stateless.js";
                    import {
                        createMintInterface,
                        createAtaInterface,
                        getAssociatedTokenAddressInterface,
                    } from "@lightprotocol/compressed-token";
                    import {
                        wrap,
                        createUnwrapInstructions,
                    } from "@lightprotocol/compressed-token/unified";
                    import {
                        TOKEN_PROGRAM_ID,
                        createAssociatedTokenAccount,
                        mintTo,
                    } from "@solana/spl-token";
                    import { homedir } from "os";
                    import { readFileSync } from "fs";

                    // devnet:
                    // const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`;
                    // const rpc = createRpc(RPC_URL);
                    // localnet:
                    const rpc = createRpc();

                    const payer = Keypair.fromSecretKey(
                        new Uint8Array(
                            JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8"))
                        )
                    );

                    (async function () {
                        // Setup: Create SPL mint, fund SPL ATA, wrap into Light ATA
                        const { mint } = await createMintInterface(
                            rpc,
                            payer,
                            payer,
                            null,
                            9,
                            undefined,
                            undefined,
                            TOKEN_PROGRAM_ID
                        );
                        const splAta = await createAssociatedTokenAccount(
                            rpc,
                            payer,
                            mint,
                            payer.publicKey,
                            undefined,
                            TOKEN_PROGRAM_ID
                        );
                        await mintTo(rpc, payer, mint, splAta, payer, 1000);

                        await createAtaInterface(rpc, payer, mint, payer.publicKey);
                        const lightTokenAta = getAssociatedTokenAddressInterface(
                            mint,
                            payer.publicKey
                        );
                        await wrap(rpc, payer, splAta, lightTokenAta, payer, mint, BigInt(1000));

                        // Create unwrap instructions
                        const instructions = await createUnwrapInstructions(
                            rpc,
                            splAta,
                            payer.publicKey,
                            mint,
                            500,
                            payer.publicKey
                        );

                        for (const ixs of instructions) {
                            const tx = new Transaction().add(...ixs);
                            const signature = await sendAndConfirmTransaction(rpc, tx, [payer]);
                            console.log("Tx:", signature);
                        }
                    })();
                    ```
                  </Tab>

                  <Tab title="SDK 2.0 (token-interface)">
                    ```typescript theme={null}
                    import { Keypair, Transaction, sendAndConfirmTransaction } from "@solana/web3.js";
                    import { createRpc } from "@lightprotocol/stateless.js";
                    import { createUnwrapInstruction, getSplInterfaces } from "@lightprotocol/token-interface";

                    const rpc = createRpc();
                    const payer = Keypair.fromSecretKey(/* ... */);

                    const mint = /* existing SPL/Token-2022 mint */;
                    const lightTokenAta = /* existing Light ATA */;
                    const splAta = /* destination SPL ATA */;

                    const splInterfaces = await getSplInterfaces(rpc, mint);
                    const splInterface =
                      splInterfaces.find((info) => info.isInitialized) ?? splInterfaces[0];
                    if (!splInterface) throw new Error("No SPL interface found");

                    const unwrapIx = createUnwrapInstruction({
                      source: lightTokenAta,
                      destination: splAta,
                      owner: payer.publicKey,
                      mint,
                      amount: 500n,
                      splInterface,
                      decimals: 9,
                      payer: payer.publicKey,
                    });

                    const tx = new Transaction().add(unwrapIx);
                    const signature = await sendAndConfirmTransaction(rpc, tx, [payer]);
                    console.log("Tx:", signature);
                    ```
                  </Tab>
                </Tabs>
              </Step>
            </Steps>
          </Tab>
        </Tabs>
      </Tab>

      <Tab title="AI Prompt">
        <Prompt description="Wrap and unwrap SPL tokens to Light Token" actions={["copy", "cursor"]}>
          {`---
                    description: Wrap and unwrap SPL tokens to Light Token
                    allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression
                    ---

                    ## Wrap and unwrap SPL tokens to Light Token

                    Context:
                    - Guide: https://zkcompression.com/light-token/cookbook/wrap-unwrap
                    - Skills and resources index: https://zkcompression.com/skill.md
                    - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison
                    - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js

                    - Wrap: Move tokens from SPL or Token 2022 account → Light Token associated token account (hot balance)
                    - Unwrap: Move tokens from Light Token associated token account (hot balance) → SPL or Token 2022 account

                    ### 1. Index project
                    - Grep \`@solana/spl-token|Connection|Keypair|wrap|unwrap|WrapTokens|UnwrapTokens\` across src/
                    - Glob \`**/*.ts\` for project structure
                    - Identify: RPC setup, existing wrap/unwrap logic, entry point for wrap/unwrap
                    - Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel

                    ### 2. Read references
                    - WebFetch the guide above — follow the TypeScript 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 wrap/unwrap operations to extend, or is this greenfield?
                    - 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 connection/signer setup is compatible with the cookbook prerequisites
                    - 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 \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js\`
                    - Follow the cookbook guide and the approved plan
                    - Write/Edit to create or modify files
                    - TaskUpdate to mark each step done

                    ### 6. Verify
                    - Bash \`tsc --noEmit\`
                    - Bash run existing test suite if present
                    - 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: Wrap and unwrap SPL tokens to Light Token
        allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression
        ---

        ## Wrap and unwrap SPL tokens to Light Token

        Context:
        - Guide: https://zkcompression.com/light-token/cookbook/wrap-unwrap
        - Skills and resources index: https://zkcompression.com/skill.md
        - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison
        - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js

        - Wrap: Move tokens from SPL or Token 2022 account → Light Token associated token account (hot balance)
        - Unwrap: Move tokens from Light Token associated token account (hot balance) → SPL or Token 2022 account

        ### 1. Index project
        - Grep `@solana/spl-token|Connection|Keypair|wrap|unwrap|WrapTokens|UnwrapTokens` across src/
        - Glob `**/*.ts` for project structure
        - Identify: RPC setup, existing wrap/unwrap logic, entry point for wrap/unwrap
        - Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel

        ### 2. Read references
        - WebFetch the guide above — follow the TypeScript 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 wrap/unwrap operations to extend, or is this greenfield?
        - 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 connection/signer setup is compatible with the cookbook prerequisites
        - 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 `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js`
        - Follow the cookbook guide and the approved plan
        - Write/Edit to create or modify files
        - TaskUpdate to mark each step done

        ### 6. Verify
        - Bash `tsc --noEmit`
        - Bash run existing test suite if present
        - 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="Rust Client">
    <Tabs>
      <Tab title="Guide">
        <Tabs>
          <Tab title="Wrap">
            <Steps>
              <Step>
                ### Prerequisites

                <Accordion title="Dependencies">
                  ```toml Cargo.toml theme={null}
                  [dependencies]
                  light-token = "0.23.0"
                  light-client = { version = "0.23.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
                          ```
                        </Tab>

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

                        <Tab title="pnpm">
                          ```bash theme={null}
                          pnpm add -g @lightprotocol/zk-compression-cli
                          ```
                        </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>
                ### Wrap SPL tokens to Light Token ATA

                <Info>
                  Find the full example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/rust-client/actions/wrap.rs).
                </Info>

                <Tabs>
                  <Tab title="Action">
                    ```rust theme={null}
                    use borsh::BorshDeserialize;
                    use light_client::rpc::Rpc;
                    use light_token_client::actions::Wrap;
                    use rust_client::{setup_for_wrap, WrapContext};

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

                        // Wrap tokens from SPL associated token account to Light Token associated token account
                        let sig = Wrap {
                            source_spl_ata: source_associated_token_account,
                            destination: light_associated_token_account,
                            mint,
                            amount: 500_000,
                            decimals,
                        }
                        .execute(&mut rpc, &payer, &payer)
                        .await?;

                        let data = rpc
                            .get_account(light_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="Unwrap">
            <Steps>
              <Step>
                ### Prerequisites

                <Accordion title="Dependencies">
                  ```toml Cargo.toml theme={null}
                  [dependencies]
                  light-token = "0.23.0"
                  light-client = { version = "0.23.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
                          ```
                        </Tab>

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

                        <Tab title="pnpm">
                          ```bash theme={null}
                          pnpm add -g @lightprotocol/zk-compression-cli
                          ```
                        </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>
                ### Unwrap Light Tokens to SPL account

                <Info>
                  Find the full example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/rust-client/actions/unwrap.rs).
                </Info>

                <Tabs>
                  <Tab title="Action">
                    ```rust theme={null}
                    use anchor_spl::token::spl_token::state::Account as SplAccount;
                    use light_client::rpc::Rpc;
                    use light_token_client::actions::Unwrap;
                    use rust_client::{setup_for_unwrap, UnwrapContext};
                    use solana_sdk::program_pack::Pack;

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

                        // Unwrap tokens from Light Token associated token account to SPL associated token account
                        let sig = Unwrap {
                            source: light_associated_token_account,
                            destination_spl_ata: destination_associated_token_account,
                            mint,
                            amount: 500_000,
                            decimals,
                        }
                        .execute(&mut rpc, &payer, &payer)
                        .await?;

                        let data = rpc
                            .get_account(destination_associated_token_account)
                            .await?
                            .ok_or("Account not found")?;
                        let token = SplAccount::unpack(&data.data)?;
                        println!("Balance: {} Tx: {sig}", token.amount);

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

      <Tab title="AI Prompt">
        <Prompt description="Wrap and unwrap SPL tokens to Light Token" actions={["copy", "cursor"]}>
          {`---
                    description: Wrap and unwrap SPL tokens to Light Token
                    allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression
                    ---

                    ## Wrap and unwrap SPL tokens to Light Token

                    Context:
                    - Guide: https://zkcompression.com/light-token/cookbook/wrap-unwrap
                    - Skills and resources index: https://zkcompression.com/skill.md
                    - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison
                    - Crates: light-token-client (actions), light-token (instructions), light-client (RPC)

                    - Wrap: move tokens from SPL or Token 2022 account → Light Token ATA (hot balance)
                    - Unwrap: move tokens from Light Token ATA (hot balance) → SPL or Token 2022 account

                    No direct SPL equivalent — Wrap/Unwrap are Light Token operations → Light Token: Wrap / Unwrap

                    ### 1. Index project
                    - Grep \`light_token::|light_token_client::|solana_sdk|Keypair|async|Wrap|Unwrap|wrap|unwrap\` across src/
                    - Glob \`**/*.rs\` for project structure
                    - Identify: RPC setup, existing token ops, entry point for wrap/unwrap
                    - 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 wrap/unwrap 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: Wrap and unwrap SPL tokens to Light Token
        allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression
        ---

        ## Wrap and unwrap SPL tokens to Light Token

        Context:
        - Guide: https://zkcompression.com/light-token/cookbook/wrap-unwrap
        - Skills and resources index: https://zkcompression.com/skill.md
        - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison
        - Crates: light-token-client (actions), light-token (instructions), light-client (RPC)

        - Wrap: move tokens from SPL or Token 2022 account → Light Token ATA (hot balance)
        - Unwrap: move tokens from Light Token ATA (hot balance) → SPL or Token 2022 account

        No direct SPL equivalent — Wrap/Unwrap are Light Token operations → Light Token: Wrap / Unwrap

        ### 1. Index project
        - Grep `light_token::|light_token_client::|solana_sdk|Keypair|async|Wrap|Unwrap|wrap|unwrap` across src/
        - Glob `**/*.rs` for project structure
        - Identify: RPC setup, existing token ops, entry point for wrap/unwrap
        - 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 wrap/unwrap 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>
</Tabs>

## Related Guides

<CardGroup cols={2}>
  <Card title="Transfer interface" icon="arrow-right-left" href="/light-token/cookbook/transfer-interface" horizontal />

  <Card title="Payments overview" icon="credit-card" href="/light-token/payments/overview" horizontal />
</CardGroup>

***

## Didn't find what you were looking for?

<Callout type="info">
  Reach out! [Telegram](https://t.me/swen_light) | [email](mailto:support@lightprotocol.com) | [Discord](https://discord.com/invite/7cJ8BhAXhu)
</Callout>
