# Migration Analysis

> Trigger Pattern Program upgrades, account data layout changes, deprecated instructions, token migrations - Inject Into Breadth agents, depth-state-trace

- Skill: `plamentsv/migration-analysis-4` (Agent Skill)
- Install (CLI): `npx skillmds@latest add plamentsv/migration-analysis-4`
- Raw SKILL.md: https://api.skillmd.com/api/skills/plamentsv/migration-analysis-4/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: plamentsv (https://skillmd.com/u/plamentsv)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/plamentsv/migration-analysis-4

---


# Skill: Migration Analysis (Solana)

> **Trigger Pattern**: Program upgrades, account data layout changes, deprecated instructions, token migrations
> **Inject Into**: Breadth agents, depth-state-trace
> **Finding prefix**: `[MG-N]`
> **Rules referenced**: S1, S3, S4, S9, R4, R9, R10

```
upgrade|authority|reinitialize|deprecated|migrat|legacy|v2|V2|old_mint|new_mint|
BPFLoaderUpgradeable|set_authority|close_account
```

## Reasoning Template

### Step 1: Identify Token and Account Transitions

Find all migration patterns:
- Old mint -> New mint (SPL Token migrations, token rebranding, Token-2022 migration)
- Deprecated instructions still callable
- Account data layout changes across program versions
- PDA seed schema changes

For each transition:
| Old Entity | New Entity | Migration Instruction | Bidirectional? | Account Type |
|------------|-----------|----------------------|----------------|-------------|

### Step 2: Check Account Data Layout Compatibility

For each program upgrade that changes account data structures:

1. What fields exist in the OLD account data layout?
2. What fields exist in the NEW account data layout?
3. Are new fields APPENDED (safe) or INSERTED/REORDERED (breaking)?
4. Does the discriminator change between versions? (Anchor uses first 8 bytes)

```rust
// Example mismatch:
// V1 layout: [discriminator(8)][authority(32)][amount(8)]  = 48 bytes
// V2 layout: [discriminator(8)][authority(32)][new_field(8)][amount(8)] = 56 bytes
// BREAKING: V1 accounts read `amount` at offset 40, but V2 expects it at offset 48
```

| Account Type | V1 Layout (fields + offsets) | V2 Layout (fields + offsets) | Compatible? | Migration Path |
|-------------|---------------------------|---------------------------|-------------|---------------|

### Step 3: Trace Account Flow Paths

For each instruction that interacts with migrated accounts:

1. **Entry point**: What account data version does the user provide?
2. **Internal flow**: What version does the program expect?
3. **CPI calls**: What version do CPI target programs expect?
4. **Return data**: What version does the program write back?

| Instruction | Account Expected | Actual Account Version | CPI Target Expects | Mismatch? |
|-------------|-----------------|----------------------|--------------------|-----------|

### Step 3b: CPI Side Effect Compatibility

When migration changes program behavior, check whether CPI callers handle the changes:

| CPI Call | Pre-Migration Behavior | Post-Migration Behavior | Caller Handles Both? | Mismatch? |
|----------|----------------------|------------------------|---------------------|-----------|

**Pattern**: Program upgrade changes return data or account mutations from a CPI, but callers were written for the old behavior. After upgrade, CPI results are misinterpreted.

### Step 3c: Pre-Upgrade Account Inventory

Before analyzing stranded asset paths, inventory all accounts the program owns:

| Account Type | How Created | Current Lamports/Tokens | Post-Upgrade Logic Handles? | Close Path Post-Upgrade? |
|-------------|------------|------------------------|----------------------------|-------------------------|
| {pda_vault} | PDA init | SOL + SPL tokens | YES/NO | {instruction or NONE} |
| {user_state} | User init | Rent-exempt SOL | YES/NO | {instruction or NONE} |
| {legacy_acct} | V1 init | Held from V1 ops | YES/NO | {instruction or NONE} |

**Pattern**: Upgrade changes which accounts the program reads/writes, but old accounts still hold SOL (rent) and tokens. If new logic cannot close or drain old accounts, assets are stranded.

### Step 4: Stranded Asset Analysis (ENHANCED)

#### 4a. Asset Inventory by Era

| Asset/Account | V1 Creation Path | V2 Creation Path | V1 Close Path | V2 Close Path |
|---------------|-----------------|-----------------|--------------|--------------|
| {pda_vault} | initialize() | initialize_v2() | close_vault() | close_vault_v2() |
| {user_account} | create_user() | create_user() | close_user() | close_user() |

**Rule**: If V1 Creation exists but V2 Close doesn't handle V1 state -> potential stranding.

#### 4b. Cross-Era Path Matrix

| Account Era | State Condition | Available Close/Drain Paths | Works? | Reason |
|-------------|----------------|---------------------------|--------|--------|
| V1 PDA vault | V2 program deployed | close_vault_v2() | Y/N | {why} |
| V1 PDA vault | V1 instruction removed | close_vault() | Y/N | {why} |
| V1 user state | In-flight during upgrade | ??? | Y/N | {why} |

**STRANDING RULE**: If ALL close/drain paths fail for any account state -> **STRANDED ASSETS FINDING**

#### 4c. Recovery Function Inventory

| Function | Who Can Call | What Accounts Can Recover | Limitations |
|----------|------------|--------------------------|-------------|
| close_account() | Authority only | Program-owned accounts | Requires active authority |
| migrate_v1() | Any user | V1 user accounts | One-time per account |
| sweep_lamports() | Authority | Unclaimed rent | Cannot recover user deposits |

#### 4d. Worst-Case Scenarios (MANDATORY)

**Scenario 1: V1 Account + V2 Program**
```
State: User created account via V1 initialize() with deposited tokens
Event: Program upgraded to V2 with new data layout
Question: Can user close/withdraw via V2 instructions?
Trace: [document instruction path and deserialization]
Result: [SUCCESS/STRANDED + amount]
```

**Scenario 2: In-Flight During Upgrade**
```
State: User initiated multi-instruction operation (e.g., unstake request) at slot N
Event: Program upgrade deployed at slot N+1
Question: Can user complete operation at slot N+2?
Trace: [document instruction path]
Result: [SUCCESS/STRANDED + amount]
```

**Scenario 3: PDA Seed Change**
```
State: PDA derived with seeds [b"vault", user.key()] in V1
Event: V2 changes seeds to [b"vault_v2", user.key()]
Question: Can V2 program access the V1 PDA? Are V1 tokens recoverable?
Trace: [document PDA derivation and account lookup]
Result: [SUCCESS/STRANDED + amount]
```

#### 4e. Step 4 Completion Checklist
- [ ] 4a: ALL accounts inventoried with creation/close paths per era
- [ ] 4b: Cross-era path matrix completed for all state combinations
- [ ] 4c: Recovery instructions enumerated with limitations
- [ ] 4d: All three worst-case scenarios modeled with traces
- [ ] For EVERY stranding possibility: recovery path exists OR finding created

### Step 4f: User-Blocks-Admin Scenarios

| Admin/Migration Instruction | Precondition Required | User Action That Blocks It | Timing Window | Severity |
|----------------------------|----------------------|---------------------------|---------------|----------|
| {admin_ix} | {precondition} | {user_action} | {window} | {assess} |

**Solana-specific patterns**:
- User creates token accounts owned by program PDA -> non-zero balance prevents PDA closure
- User initiates pending operations (unstake, withdrawal request) -> in-flight state blocks migration
- User creates many small accounts -> iteration over accounts exceeds CU limit for admin migration instruction

### Step 5: Upgrade Authority Lifecycle

| Check | Status | Evidence |
|-------|--------|----------|
| Upgrade authority identified? | {pubkey or multisig} | {source location} |
| Is authority a multisig (Squads)? | YES/NO | |
| Can authority be revoked (program made immutable)? | YES/NO | |
| If revoked: are all config parameters frozen? | YES/NO | |
| If revoked: can stranded assets be recovered? | YES/NO | Apply Rule 9 |
| Buffer validation during upgrade? | YES/NO | Can malicious buffer be substituted? |
| IDL discriminator stability? | YES/NO | Changed discriminators break all callers |

### Step 6: Downstream Integration Compatibility

| Program Change | Downstream Consumer | Expected Interface | Post-Migration Actual | Breaking? |
|---------------|--------------------|--------------------|----------------------|-----------|
| {change} | CPI callers | {expected IDL} | {actual IDL} | YES/NO |
| {change} | Indexers (Geyser, Helius) | {expected account layout} | {actual layout} | YES/NO |
| {change} | Frontend/SDK | {expected instruction format} | {actual} | YES/NO |

**Pattern**: Program upgrade changes instruction discriminators, account layouts, or CPI behavior, but downstream consumers (other programs calling via CPI, indexers, SDKs) were built for the old interface.

## Key Questions (Must Answer All)
1. **Data Layout**: Are ALL existing accounts readable by the new program version?
2. **PDA Stability**: Do ALL PDAs remain derivable with the same seeds after upgrade?
3. **Migration Completeness**: Can ALL V1 accounts be migrated/closed via V2 paths?
4. **Stranded Assets**: Is there any combination of (old_account_state + new_program) that traps funds?
5. **Authority Lifecycle**: Is the upgrade authority appropriately secured and revocable?

## Common False Positives
1. **Append-only layout changes**: New fields added at end with defaults -- backward compatible
2. **Versioned deserialization**: Program explicitly handles both V1 and V2 layouts
3. **Admin-controlled migration**: Stranded accounts recoverable via authority instructions

## Finding Template

```markdown
**ID**: [MG-N]
**Verdict**: CONFIRMED / PARTIAL / REFUTED / CONTESTED
**Step Execution**: (see checklist below)
**Rules Applied**: [S1:___, S3:___, S4:___, S9:___, R4:___, R9:___, R10:___]
**Severity**: Critical/High/Medium/Low/Info
**Location**: programs/{program}/src/{file}.rs:LineN

**Account Transition**:
- Old: {old_layout/mint/PDA}
- New: {new_layout/mint/PDA}
- Mismatch Point: {where layouts/seeds diverge}

**Description**: {what is wrong}
**Impact**: {stranded funds, corrupted state, broken CPI callers}
**Evidence**: {code showing mismatch}
```

---

## Step Execution Checklist (MANDATORY)

| Step | Required | Completed? | Notes |
|------|----------|------------|-------|
| 1. Identify Token and Account Transitions | YES | | |
| 2. Check Account Data Layout Compatibility | YES | | |
| 3. Trace Account Flow Paths | YES | | |
| 3b. CPI Side Effect Compatibility | YES | | |
| 3c. Pre-Upgrade Account Inventory | YES | | |
| 4. Stranded Asset Analysis (4a-4e) | YES | | |
| 4f. User-Blocks-Admin Scenarios | YES | | |
| 5. Upgrade Authority Lifecycle | YES | | |
| 6. Downstream Integration Compatibility | YES | | |

If any step skipped, document valid reason (N/A, immutable program, single version, no CPI callers).

