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
Context
core::InstructionView(src/chain_parsers/visualsign-solana/src/core/mod.rs:231) is the canonical way to turn aVisualizerContextinto display-ready program and account strings. It resolves every account index to one of three forms (core/mod.rs:240-248):Four presets hand-roll that same three-arm match instead of using it, and all four diverge on the
Nonearm:presets/jupiter_swap/mod.rs:94None => "unknown".to_string()presets/system/mod.rs:123None => "unknown".to_string()presets/system/mod.rs:128None => "unknown".to_string()presets/unknown_program/mod.rs:67None => "unknown".to_string()Each site looks like:
Impact
Two problems, one cause.
Inconsistent output. An out-of-bounds account index renders as
unknownin these four places and asunresolved(oob:N)everywhere else. A signer comparing two transactions sees different placeholder vocabulary for the same condition, andunknowndoes 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
coresilently leaves these four behind. That is exactly how the divergence arose:spl_tokencarried the same stale arm until #381 migrated it, and the remaining four were out of that issue's scope (#380 is scoped tospl_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:63already wraps this asresolve_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:2045and:2055also return"unknown", but fromprogram_scope_type_nameandnumeric_type_name-- enum-name mapping for unrecognized discriminants, unrelated to account resolution. Leave them alone.Verification