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 |
- TypeScript
- Rust
- Pinocchio
- AI Prompt
Update imports
Report incorrect code
Copy
Ask AI
// v1
import {
deriveAddress,
deriveAddressSeed,
defaultTestStateTreeAccounts,
PackedAccounts,
} from "@lightprotocol/stateless.js";
Report incorrect code
Copy
Ask AI
// v2
import {
deriveAddressV2,
deriveAddressSeedV2,
batchAddressTree,
PackedAccounts,
featureFlags,
VERSION,
} from "@lightprotocol/stateless.js";
Enable v2 mode
Set the feature flag before making any calls:Report incorrect code
Copy
Ask AI
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:Report incorrect code
Copy
Ask AI
// v1 - Program ID passed to seed derivation
const seed = deriveAddressSeed(
[counterSeed, signer.publicKey.toBytes()],
new PublicKey(program.idl.address)
);
const address = deriveAddress(seed, addressTree);
Report incorrect code
Copy
Ask AI
// 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
UsebatchAddressTree instead of defaultTestStateTreeAccounts().addressTree:Report incorrect code
Copy
Ask AI
// v1
const addressTree = defaultTestStateTreeAccounts().addressTree;
const addressQueue = defaultTestStateTreeAccounts().addressQueue;
// In proof request
{
tree: addressTree,
queue: addressQueue,
address: bn(address.toBytes()),
}
Report incorrect code
Copy
Ask AI
// 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:Report incorrect code
Copy
Ask AI
// v1
const remainingAccounts = PackedAccounts.newWithSystemAccounts(systemAccountConfig);
Report incorrect code
Copy
Ask AI
// v2
const remainingAccounts = PackedAccounts.newWithSystemAccountsV2(systemAccountConfig);
Update Cargo.toml
Add thev2 feature flag to your dependencies:Report incorrect code
Copy
Ask AI
[dependencies]
light-sdk = { version = "0.16", features = ["v2"] }
light-sdk-types = { version = "0.3", features = ["v2"] }
Update imports
Report incorrect code
Copy
Ask AI
// v1
use light_sdk::{
address::v1::derive_address,
constants::ADDRESS_TREE_V1,
cpi::v1::{CpiAccounts, LightSystemProgramCpi},
};
Report incorrect code
Copy
Ask AI
// v2
use light_sdk::{
address::v2::derive_address,
cpi::v2::{CpiAccounts, LightSystemProgramCpi},
};
use light_sdk_types::ADDRESS_TREE_V2;
Update address derivation
Thederive_address function signature remains the same, but the internal derivation logic differs. No code changes needed beyond updating the import path.Update address params
Replaceinto_new_address_params_packed() with into_new_address_params_assigned_packed():Report incorrect code
Copy
Ask AI
// v1
let new_address_params = instruction_data
.address_tree_info
.into_new_address_params_packed(address_seed);
Report incorrect code
Copy
Ask AI
// v2
let new_address_params = instruction_data
.address_tree_info
.into_new_address_params_assigned_packed(address_seed, Some(0));
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:Report incorrect code
Copy
Ask AI
// v1
if address_tree_pubkey.to_bytes() != ADDRESS_TREE_V1 {
return Err(ProgramError::InvalidAccountData);
}
Report incorrect code
Copy
Ask AI
// v2
if address_tree_pubkey.to_bytes() != ADDRESS_TREE_V2 {
return Err(ProgramError::InvalidAccountData);
}
The Pinocchio SDK follows the same import changes as the Rust SDK, plus one additional API change.
Update imports
Report incorrect code
Copy
Ask AI
// v1
use light_sdk_pinocchio::{
address::v1::derive_address,
constants::ADDRESS_TREE_V1,
cpi::v1::{CpiAccounts, LightSystemProgramCpi},
};
Report incorrect code
Copy
Ask AI
// 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):Report incorrect code
Copy
Ask AI
// v1
let cpi_accounts = CpiAccounts::try_new_with_config(signer, &accounts[1..], config)
.map_err(to_custom_error_u32)?;
Report incorrect code
Copy
Ask AI
// v2
let cpi_accounts = CpiAccounts::new_with_config(signer, &accounts[1..], config);
Update address params
Same as the Rust SDK:Report incorrect code
Copy
Ask AI
// v1
let new_address_params = instruction_data
.address_tree_info
.into_new_address_params_packed(address_seed);
Report incorrect code
Copy
Ask AI
// v2
let new_address_params = instruction_data
.address_tree_info
.into_new_address_params_assigned_packed(address_seed, Some(0));
Report incorrect code
Copy
Ask AI
---
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?")