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

# Guide to Migrate from v1 to v2 Merkle trees

> V2 reduces CU consumption by up to 70%. V1 remains supported for existing deployments.

## V2 Improvements

|                       | v1                    | v2                |
| --------------------- | --------------------- | ----------------- |
| Merkle tree type      | Concurrent            | Batched           |
| State tree depth      | 26 (\~67M leaves)     | 32 (\~4B leaves)  |
| Address tree depth    | 26                    | 40                |
| Address tree accounts | Separate tree + queue | Single batch tree |

<Tabs>
  <Tab title="TypeScript">
    ### Update imports

    ```typescript theme={null}
    // v1
    import {
        deriveAddress,
        deriveAddressSeed,
        defaultTestStateTreeAccounts,
        PackedAccounts,
    } from "@lightprotocol/stateless.js";
    ```

    ```typescript theme={null}
    // v2
    import {
        deriveAddressV2,
        deriveAddressSeedV2,
        batchAddressTree,
        PackedAccounts,
        featureFlags,
        VERSION,
    } from "@lightprotocol/stateless.js";
    ```

    ### Enable v2 mode

    Set the feature flag before making any calls:

    ```typescript theme={null}
    import { featureFlags, VERSION } from "@lightprotocol/stateless.js";

    (featureFlags as any).version = VERSION.V2;
    ```

    ### Update address derivation

    The seed and address derivation functions have different signatures in v2:

    ```typescript theme={null}
    // v1 - Program ID passed to seed derivation
    const seed = deriveAddressSeed(
        [counterSeed, signer.publicKey.toBytes()],
        new PublicKey(program.idl.address)
    );
    const address = deriveAddress(seed, addressTree);
    ```

    ```typescript theme={null}
    // v2 - Program ID passed to address derivation
    const seed = deriveAddressSeedV2([counterSeed, signer.publicKey.toBytes()]);
    const address = deriveAddressV2(
        seed,
        addressTree,
        new PublicKey(program.idl.address)
    );
    ```

    ### Update address tree references

    Use `batchAddressTree` instead of `defaultTestStateTreeAccounts().addressTree`:

    ```typescript theme={null}
    // v1
    const addressTree = defaultTestStateTreeAccounts().addressTree;
    const addressQueue = defaultTestStateTreeAccounts().addressQueue;

    // In proof request
    {
        tree: addressTree,
        queue: addressQueue,
        address: bn(address.toBytes()),
    }
    ```

    ```typescript theme={null}
    // v2 - queue equals tree for batch trees
    const addressTree = new PublicKey(batchAddressTree);

    // In proof request
    {
        tree: addressTree,
        queue: addressTree,
        address: bn(address.toBytes()),
    }
    ```

    ### Update PackedAccounts

    Use the v2 variant when building remaining accounts:

    ```typescript theme={null}
    // v1
    const remainingAccounts = PackedAccounts.newWithSystemAccounts(systemAccountConfig);
    ```

    ```typescript theme={null}
    // v2
    const remainingAccounts = PackedAccounts.newWithSystemAccountsV2(systemAccountConfig);
    ```
  </Tab>

  <Tab title="Rust">
    ### Update Cargo.toml

    Add the `v2` feature flag to your dependencies:

    ```toml theme={null}
    [dependencies]
    light-sdk = { version = "0.16", features = ["v2"] }
    light-sdk-types = { version = "0.3", features = ["v2"] }
    ```

    ### Update imports

    ```rust theme={null}
    // v1
    use light_sdk::{
        address::v1::derive_address,
        constants::ADDRESS_TREE_V1,
        cpi::v1::{CpiAccounts, LightSystemProgramCpi},
    };
    ```

    ```rust theme={null}
    // v2
    use light_sdk::{
        address::v2::derive_address,
        cpi::v2::{CpiAccounts, LightSystemProgramCpi},
    };
    use light_sdk_types::ADDRESS_TREE_V2;
    ```

    ### Update address derivation

    The `derive_address` function signature remains the same, but the internal derivation logic differs. No code changes needed beyond updating the import path.

    ### Update address params

    Replace `into_new_address_params_packed()` with `into_new_address_params_assigned_packed()`:

    ```rust theme={null}
    // v1
    let new_address_params = instruction_data
        .address_tree_info
        .into_new_address_params_packed(address_seed);
    ```

    ```rust theme={null}
    // v2
    let new_address_params = instruction_data
        .address_tree_info
        .into_new_address_params_assigned_packed(address_seed, Some(0));
    ```

    The second parameter specifies the output queue index. Use `Some(0)` to assign the address to the first available queue.

    ### Update tree validation

    If your program validates the address tree pubkey, update the constant:

    ```rust theme={null}
    // v1
    if address_tree_pubkey.to_bytes() != ADDRESS_TREE_V1 {
        return Err(ProgramError::InvalidAccountData);
    }
    ```

    ```rust theme={null}
    // v2
    if address_tree_pubkey.to_bytes() != ADDRESS_TREE_V2 {
        return Err(ProgramError::InvalidAccountData);
    }
    ```
  </Tab>

  <Tab title="Pinocchio">
    The Pinocchio SDK follows the same import changes as the Rust SDK, plus one additional API change.

    ### Update imports

    ```rust theme={null}
    // v1
    use light_sdk_pinocchio::{
        address::v1::derive_address,
        constants::ADDRESS_TREE_V1,
        cpi::v1::{CpiAccounts, LightSystemProgramCpi},
    };
    ```

    ```rust theme={null}
    // v2
    use light_sdk_pinocchio::{
        address::v2::derive_address,
        cpi::v2::{CpiAccounts, LightSystemProgramCpi},
    };
    use light_sdk_types::ADDRESS_TREE_V2;
    ```

    ### Update CpiAccounts

    `CpiAccounts::try_new_with_config()` becomes `CpiAccounts::new_with_config()` (infallible):

    ```rust theme={null}
    // v1
    let cpi_accounts = CpiAccounts::try_new_with_config(signer, &accounts[1..], config)
        .map_err(to_custom_error_u32)?;
    ```

    ```rust theme={null}
    // v2
    let cpi_accounts = CpiAccounts::new_with_config(signer, &accounts[1..], config);
    ```

    ### Update address params

    Same as the Rust SDK:

    ```rust theme={null}
    // v1
    let new_address_params = instruction_data
        .address_tree_info
        .into_new_address_params_packed(address_seed);
    ```

    ```rust theme={null}
    // v2
    let new_address_params = instruction_data
        .address_tree_info
        .into_new_address_params_assigned_packed(address_seed, Some(0));
    ```
  </Tab>

  <Tab title="AI Prompt">
    ```text theme={null}
    ---
    argument-hint: <path_to_program>
    description: Migrate Light Protocol program from v1 to v2 Merkle trees
    allowed-tools: [Bash, Read, Glob, Grep, Task, WebFetch]
    ---

    Migrate this Light Protocol program from v1 to v2 Merkle trees.

    ## Goal

    Produce a **fully working migration** that builds and tests pass.

    ## Available commands

    Via Bash tool:
    - **cargo build-sbf**, **cargo test-sbf**, **cargo fmt**, **cargo clippy**
    - **anchor build**, **anchor test**
    - **grep**, **sed**

    ## Documentation

    - Migration Guide: https://zkcompression.com/references/migration-v1-to-v2
    - Reference PR: https://github.com/Lightprotocol/program-examples/commit/54f0e7f15c2972a078f776cfb40b238d83c7e486

    ## Reference repos

    program-examples/counter/anchor/
    ├── programs/counter/src/lib.rs    # v2 patterns: derive_address, CpiAccounts
    ├── Cargo.toml                      # v2 feature flags
    └── tests/counter.ts                # v2 client patterns

    ## Workflow

    ### Phase 1: Index program

    Find all v1 patterns:

        grep -r "::v1::" src/ tests/
        grep -r "ADDRESS_TREE_V1" src/
        grep -r "into_new_address_params_packed" src/
        grep -r "get_address_tree_v1" tests/

    ### Phase 2: Update dependencies

    Add v2 feature to Cargo.toml:

        [dependencies]
        light-sdk = { version = "0.17", features = ["anchor", "v2"] }
        light-sdk-types = { version = "0.17", features = ["v2"] }

        [dev-dependencies]
        light-program-test = { version = "0.17", features = ["v2"] }
        light-client = { version = "0.17", features = ["v2"] }

    ### Phase 3: Rust SDK replacements

    | v1 Pattern | v2 Replacement |
    |------------|----------------|
    | address::v1::derive_address | address::v2::derive_address |
    | cpi::v1::CpiAccounts | cpi::v2::CpiAccounts |
    | cpi::v1::LightSystemProgramCpi | cpi::v2::LightSystemProgramCpi |
    | constants::ADDRESS_TREE_V1 | light_sdk_types::ADDRESS_TREE_V2 |
    | .into_new_address_params_packed(seed) | .into_new_address_params_assigned_packed(seed, Some(0)) |
    | .add_system_accounts(config) | .add_system_accounts_v2(config) |

    ### Phase 4: TypeScript SDK replacements

    | v1 Pattern | v2 Replacement |
    |------------|----------------|
    | deriveAddress( | deriveAddressV2( |
    | deriveAddressSeed( | deriveAddressSeedV2( |
    | defaultTestStateTreeAccounts().addressTree | batchAddressTree |
    | .newWithSystemAccounts( | .newWithSystemAccountsV2( |
    | get_address_tree_v1() | get_address_tree_v2() |
    | get_random_state_tree_info_v1() | get_random_state_tree_info() |

    ### Phase 5: Build and test loop

    **Required commands (no shortcuts):**

    For Anchor programs: **anchor build && anchor test**

    For Native programs: **cargo build-sbf && cargo test-sbf**

    **NO shortcuts allowed:**

    - Do NOT use **cargo build** (must use **cargo build-sbf**)
    - Do NOT use **cargo test** (must use **cargo test-sbf**)
    - Tests MUST run against real BPF bytecode

    **On failure:** Spawn debugger agent with error context.

    **Loop rules:**

    1. Each debugger gets fresh context + previous debug reports
    2. Each attempt tries something DIFFERENT
    3. **NEVER GIVE UP** - keep spawning until fixed

    Do NOT proceed until all tests pass.

    ## DeepWiki fallback

    If no matching pattern in reference repos:

        mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "How to migrate {pattern} from v1 to v2?")
    ```
  </Tab>
</Tabs>

## View Program Examples

<Card title="Program examples" icon="chevron-right" color="#0066ff" href="/compressed-pdas/program-examples" horizontal />
