Skip to content

feat: resolve token batch inner instructions in inspector#916

Open
askov wants to merge 3 commits intosolana-foundation:masterfrom
hoodieshq:feat/token-batch-inspector-inner-instructions
Open

feat: resolve token batch inner instructions in inspector#916
askov wants to merge 3 commits intosolana-foundation:masterfrom
hoodieshq:feat/token-batch-inspector-inner-instructions

Conversation

@askov
Copy link
Copy Markdown
Contributor

@askov askov commented Apr 1, 2026

Description

Thread compiled inner instructions through the inspector so that token batch CPI calls are decoded and rendered as inner cards on unknown program instructions.

Type of change

  • New feature

Screenshots

localhost_3000_tx_3QZN2MpbYqxHp32fubqUANs2b1YSBJKQQr3BXSzziWkbjzeCaGgYLikCA24sUmmbgcxE45wisJahmxMfZDr8geS5_inspect_cluster=testnet (1)-2

Testing

Related Issues

Closes HOO-386

Checklist

  • My code follows the project's style guidelines
  • I have added tests that prove my fix/feature works
  • All tests pass locally and in CI
  • I have run build:info script to update build information
  • CI/CD checks pass
  • I have included screenshots for protocol screens (if applicable)

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 1, 2026

@askov is attempting to deploy a commit to the Solana Foundation Team on Vercel.

A member of the Team first needs to authorize it.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 1, 2026

Greptile Summary

This PR threads compiled inner instructions (CompiledInnerInstruction[]) from the transaction RPC response through the inspector pipeline so that token-batch CPI calls made by unknown programs are decoded and rendered as nested TokenBatchCard components inside the UnknownDetailsCard.

Key changes:

  • raw.tsx: innerInstructions is now fetched from response.meta and surfaced through the Details interface.
  • InspectorPage.tsx: compiledInnerInstructions is added to TransactionData and wired from PermalinkViewLoadedViewInstructionsSection.
  • resolveInnerBatchInstructions (new): Groups compiled inner instructions by parent index, keeping only token-batch ones, using the new compiledToTransactionInstruction helper for index→pubkey resolution.
  • InstructionsSection: Computes batchByIndex and passes the resolved cards as innerCards to InspectorInstructionCard, which ultimately forwards them to UnknownDetailsCard.
  • UnknownDetailsCard: Accepts the optional innerCards prop and auto-expands when they are present.
  • Test coverage for the new resolveInnerBatchInstructions utility is thorough and well-structured.

Minor notes:

  • innerCards is only forwarded to UnknownDetailsCard (the PR's stated scope); all named-program cards and the Anchor path silently discard them — by design, but worth a comment in code.
  • The AnchorDetailsCard error-boundary fallback renders UnknownDetailsCard without innerCards, so the degraded Anchor path loses inner batch cards if rendering throws.

Confidence Score: 5/5

Safe to merge — all remaining findings are P2 style suggestions with no impact on the primary user path.

The core feature is correctly implemented and well-tested. The only issues found are P2: the Anchor error-boundary fallback drops inner cards in an already-degraded path, and inner cards are intentionally not forwarded to named-program card types. No runtime errors, data loss, or security concerns were identified.

app/components/inspector/InstructionsSection.tsx — Anchor fallback does not forward innerCards; all other files look clean.

Important Files Changed

Filename Overview
app/features/token-batch/lib/resolve-inner-batch-instructions.ts New utility that groups compiled inner instructions by parent index, filtering to only token-batch instructions. Logic is clean and correct; handles out-of-range indices by returning undefined via compiledToTransactionInstruction.
app/features/token-batch/lib/compiled-to-transaction-instruction.ts Correctly converts index-based CompiledInstruction to pubkey-based TransactionInstruction; properly decodes base58 data, resolves signer/writable flags from VersionedMessage, and returns undefined on any out-of-range index.
app/components/inspector/InstructionsSection.tsx Threads compiledInnerInstructions through to UnknownDetailsCard as innerCards; innerCards are silently dropped for all other card types (Anchor, named programs), and the AnchorDetailsCard ErrorBoundary fallback doesn't forward innerCards.
app/components/inspector/UnknownDetailsCard.tsx Cleanly adds optional innerCards prop; auto-expands the card when inner cards are present; renders them under an Inner Instructions row in the table body.
app/providers/transactions/raw.tsx Adds innerInstructions to the Details interface and fetches it from the RPC response; null to undefined coercion via ?? undefined is correct and necessary.
app/features/token-batch/lib/tests/resolve-inner-batch-instructions.spec.ts Well-structured tests covering the happy path, non-batch filtering, signer/writable flag resolution, multiple parent indices, out-of-range indices, and empty input.
app/components/inspector/InspectorPage.tsx Correctly propagates compiledInnerInstructions from PermalinkView through TransactionData to InstructionsSection; type addition and wiring are clean.

Sequence Diagram

sequenceDiagram
    participant RPC as Solana RPC
    participant Raw as raw.tsx (fetchRawTransaction)
    participant Page as InspectorPage (PermalinkView)
    participant Section as InstructionsSection
    participant Resolve as resolveInnerBatchInstructions
    participant Compile as compiledToTransactionInstruction
    participant Card as UnknownDetailsCard

    RPC-->>Raw: VersionedTransactionResponse (meta.innerInstructions)
    Raw-->>Page: Details { raw.meta.innerInstructions }
    Page-->>Section: compiledInnerInstructions
    Section->>Resolve: compiledInnerInstructions, accountKeys, message
    loop for each CompiledInnerInstruction
        Resolve->>Compile: CompiledInstruction
        Compile-->>Resolve: TransactionInstruction or undefined
    end
    Resolve-->>Section: Record(parentIndex to TransactionInstruction[])
    Section->>Card: innerCards (TokenBatchCard nodes per parent index)
    Card-->>Card: auto-expand + render Inner Instructions section
Loading

Comments Outside Diff (1)

  1. app/components/inspector/InstructionsSection.tsx, line 122-124 (link)

    P2 Anchor fallback loses resolved inner cards

    When AnchorDetailsCard throws and the ErrorBoundary activates, the fallback UnknownDetailsCard is rendered without the innerCards computed from batchByIndex. If an Anchor program CPIs into a token-batch instruction and Anchor card rendering fails, the inner batch cards are silently lost in the degraded path.

    Consider forwarding the inner cards to the fallback so the degraded view stays consistent with the UnknownDetailsCard behaviour used at the bottom of the function.

Reviews (1): Last reviewed commit: "feat: resolve token batch inner instruct..." | Re-trigger Greptile

Comment thread app/components/inspector/InstructionsSection.tsx
@askov askov force-pushed the feat/token-batch-inspector-inner-instructions branch from 06ca009 to 1409230 Compare April 1, 2026 14:20
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
explorer Ready Ready Preview, Comment Apr 10, 2026 6:40pm

Request Review

@askov askov force-pushed the feat/token-batch-inspector-inner-instructions branch from 18a63b8 to c456350 Compare April 6, 2026 06:57
}

return new TransactionInstruction({
data: bs58.decode(ix.data),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe we need a try/catch here. I agree the instruction data from RPC will not likely be in base58, but a manual call to it might trigger an exception

Comment thread bench/BUILD.md Outdated
| Dynamic | `/api/domain-info/[domain]` | 0 B | 0 B |
| Dynamic | `/api/geo-location` | 0 B | 0 B |
| Dynamic | `/api/metadata/proxy` | 0 B | 0 B |
| Static | `/api/metadata/proxy` | 0 B | 0 B |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proxy will be static. That is likely fixed at master

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Copy link
Copy Markdown
Contributor

@rogaldh rogaldh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants