Agent skill
migration-analysis
Trigger Pattern Program upgrades, account data layout changes, deprecated instructions, token migrations - Inject Into Breadth agents, depth-state-trace
Install this agent skill to your Project
npx add-skill https://github.com/PlamenTSV/plamen/tree/main/agents/skills/solana/migration-analysis
SKILL.md
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:
- What fields exist in the OLD account data layout?
- What fields exist in the NEW account data layout?
- Are new fields APPENDED (safe) or INSERTED/REORDERED (breaking)?
- Does the discriminator change between versions? (Anchor uses first 8 bytes)
// 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:
- Entry point: What account data version does the user provide?
- Internal flow: What version does the program expect?
- CPI calls: What version do CPI target programs expect?
- 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)
- Data Layout: Are ALL existing accounts readable by the new program version?
- PDA Stability: Do ALL PDAs remain derivable with the same seeds after upgrade?
- Migration Completeness: Can ALL V1 accounts be migrated/closed via V2 paths?
- Stranded Assets: Is there any combination of (old_account_state + new_program) that traps funds?
- Authority Lifecycle: Is the upgrade authority appropriately secured and revocable?
Common False Positives
- Append-only layout changes: New fields added at end with defaults -- backward compatible
- Versioned deserialization: Program explicitly handles both V1 and V2 layouts
- Admin-controlled migration: Stranded accounts recoverable via authority instructions
Finding Template
**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).
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
integration-hazard-research
Protocol Type Trigger NAMED_EXTERNAL_PROTOCOL (detected when recon finds import/interface for an identifiable external protocol — not standard libraries). Researches known integration hazards of the target protocol.
outcome-determinism
Protocol Type Trigger outcome_determinism - detected when EITHER of these code patterns are present - - Selection from finite depletable pool with fallback behavior (while(full)...
governance-attack-vectors
Protocol Type Trigger governance (detected when Governor, Timelock, voting, proposal, quorum, delegate patterns found) - Inject Into Breadth agents, depth-external, depth-edge-case
vault-accounting
Protocol Type Trigger vault (detected in recon TASK 0 Step 1) - Inject Into Core state agent OR economic design agent (merge via M4 hierarchy)
lending-protocol-security
Protocol Type Trigger lending (detected when recon finds liquidate|borrow|repay|collateral|lend|loan|LTV|healthFactor|interestRate|debtToken) - Inject Into Breadth agents, depth...
dex-integration-security
Protocol Type Trigger dex_integration (detected when recon finds swap|addLiquidity|removeLiquidity|IUniswapV2Router|ISwapRouter|amountOutMin|amountOutMinimum|slippage - AND the...
Didn't find tool you were looking for?