Skip to content

solana: four presets hand-roll account resolution and render "unknown" instead of the canonical unresolved placeholder #435

Description

Context

core::InstructionView (src/chain_parsers/visualsign-solana/src/core/mod.rs:231) is the canonical way to turn a VisualizerContext into display-ready program and account strings. It resolves every account index to one of three forms (core/mod.rs:240-248):

ProgramRef::Unresolved { raw_index }        => format!("unresolved({raw_index})"),
Some(AccountRef::Unresolved { raw_index })  => format!("unresolved({raw_index})"),
None                                        => format!("unresolved(oob:{i})"),

Four presets hand-roll that same three-arm match instead of using it, and all four diverge on the None arm:

Location Divergence
presets/jupiter_swap/mod.rs:94 None => "unknown".to_string()
presets/system/mod.rs:123 None => "unknown".to_string()
presets/system/mod.rs:128 None => "unknown".to_string()
presets/unknown_program/mod.rs:67 None => "unknown".to_string()

Each site looks like:

match context.account(i) {
    Some(AccountRef::Resolved(pk)) => pk.to_string(),
    Some(AccountRef::Unresolved { raw_index }) => format!("unresolved({raw_index})"),
    None => "unknown".to_string(),
}

Impact

Two problems, one cause.

Inconsistent output. An out-of-bounds account index renders as unknown in these four places and as unresolved(oob:N) everywhere else. A signer comparing two transactions sees different placeholder vocabulary for the same condition, and unknown does not carry the index that makes the condition diagnosable.

Duplicated logic drifts. The resolution rule lives in five places, so a change to the canonical form in core silently leaves these four behind. That is exactly how the divergence arose: spl_token carried the same stale arm until #381 migrated it, and the remaining four were out of that issue's scope (#380 is scoped to spl_token).

Proposed fix

Replace the four hand-rolled closures with the shared path -- either core::InstructionView::from_context(context) where a preset wants all accounts, or a small shared helper on the context for single-position lookups (presets/unknown_program/mod.rs:63 already wraps this as resolve_account_str, which is the natural home).

Once the four call sites route through core, the "unknown" literal disappears from account resolution and the placeholder rule has exactly one definition.

Out of scope

presets/swig_wallet/mod.rs:2045 and :2055 also return "unknown", but from program_scope_type_name and numeric_type_name -- enum-name mapping for unrecognized discriminants, unrelated to account resolution. Leave them alone.

Verification

# after the change, account-resolution "unknown" fallbacks are gone
cd src/chain_parsers/visualsign-solana/src
grep -rn '=> "unknown"\|"unknown"\.to_string()' --include=*.rs .
# expect only the two swig_wallet enum-name sites

cargo test -p visualsign-solana

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions