Add Exponent Finance Solana visualizer preset#275
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a dedicated Solana visualizer preset for the Exponent Finance core program so transactions no longer fall back to the generic unknown_program rendering and instead show decoded instruction names, named accounts, and decoded arguments using the bundled IDL.
Changes:
- Registered a new
presets::exponent_financemodule undervisualsign-solana. - Implemented an IDL-driven instruction parser/visualizer (matching the existing generic-IDL scaffold pattern used by other presets).
- Added the Exponent Finance IDL JSON (with the documented
Numberstruct field naming adaptation) and a program config mapping for dispatch.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/chain_parsers/visualsign-solana/src/presets/mod.rs |
Registers the new exponent_finance preset module. |
src/chain_parsers/visualsign-solana/src/presets/exponent_finance/mod.rs |
Implements the Exponent Finance IDL-backed visualizer, parsing, field building, and unit tests. |
src/chain_parsers/visualsign-solana/src/presets/exponent_finance/config.rs |
Adds Solana integration config mapping the Exponent program ID to all instructions. |
src/chain_parsers/visualsign-solana/src/presets/exponent_finance/exponent_finance.json |
Bundles the Exponent Finance IDL used for decoding instruction discriminators/args/accounts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
2b94a20 to
668f35e
Compare
prasanna-anchorage
left a comment
There was a problem hiding this comment.
Approving. Rebased onto current main — the diff was reverting #284's pub mod kamino_limit; registration because the PR predates that merge. Resolved the presets/mod.rs conflict by keeping both exponent_finance and kamino_limit in alphabetical order.
Verification:
cargo clippy -p visualsign-solana --all-targets -- -D warnings: clean.- 4 exponent_finance preset tests pass (
test_exponent_finance_idl_loads,test_exponent_finance_idl_has_discriminators,test_unknown_discriminator_returns_error,test_short_data_returns_error). - Same preset template as the 11 other Kyle-authored Solana presets already on main.
config.rs uses HashMap per the current convention — #288's sweep will flip it to BTreeMap when that PR lands.
#297) PR #288 forbade std::collections::HashMap/HashSet via clippy disallowed-types and converted the existing preset configs to BTreeMap, but missed the two presets that landed during the same review window: - exponent_finance (PR #275, merged 2026-05-12 22:00 UTC) - kamino_limit (PR #284, merged 2026-05-11 14:50 UTC) Both still constructed HashMap and passed it where SolanaIntegrationConfigData now expects BTreeMap, so `cargo build -p visualsign-solana` fails on post-#288 main. Verified locally: `cargo build -p visualsign-solana` and `cargo clippy -p visualsign-solana --all-targets -- -D warnings` are clean; `cargo fmt --check` passes. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merges origin/main (3bbf4e7) into the PR #255 branch. Resolves three content conflicts and ports two new presets from main to the wire-data VisualizerContext API introduced by PR #255. Conflicts resolved: - .gitignore: keep both `docs/superpowers/` (PR #255) and `.surfpool/` (main, from #294). - src/chain_parsers/visualsign-solana/src/presets/dflow_aggregator/mod.rs: take main's #286 changes (remaining-accounts surfacing, nested-arg flattening, `mut expanded_fields` + warn-on-parse-fail) on top of PR #255's wire-data API. The raw-data field is now pushed in place via `expanded_fields.push(create_raw_data_field(data, ...))` using `context.data()` instead of the removed `instruction.data`. - src/chain_parsers/visualsign-solana/src/presets/unknown_program/mod.rs: combine main's #288 determinism fix (locally-built `BTreeMap<String, String>` returned alongside the parsed payload, iterated at render time instead of `parsed.named_accounts`'s upstream `HashMap`) with PR #255's wire-data API (`context.program_id()`, `context.data()`, `context.num_accounts()`, `resolve_account_str(context, i)`). Imports remain `BTreeMap`; `HashMap` is no longer referenced. Two new presets ported to the wire-data API (same pattern as the existing `80b076b` port commit): - exponent_finance (from main #275): `current_instruction()` / `instruction.{program_id,data,accounts}` replaced by `context.resolve_program_id()?`, `context.resolve_accounts()?`, `context.data()`. Inline `expanded_fields.push(create_raw_data_field(...))` pattern; the unused `append_raw_data` helper deleted. - kamino_limit (from main #284): same API port. Function helpers (`build_named_accounts`, `build_parsed_fields`, `build_fallback_fields`, `append_raw_data`) retained -- they take `data: &[u8]` and `accounts: &[AccountMeta]` and remain useful. Both new presets' `config.rs` switched from `std::collections::HashMap` to `std::collections::BTreeMap` to satisfy main's #288 disallowed-types lint and the `SolanaIntegrationConfigData.programs: BTreeMap<...>` field shape. Verified: - cargo fmt clean - cargo check --workspace --exclude parser_cli clean - cargo check -p parser_cli clean - cargo test -p visualsign-solana --lib: 148 passed, 0 failed Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Why this PR exists
Solana transactions calling the Exponent Finance core program (
ExponentnaRg3CQbW6dqQNZKXp7gtZ9DGMp1cwC4HAS7) currently fall through to the genericunknown_programvisualizer, so wallet sign prompts show only the program ID and raw hex instruction data. This adds a dedicated preset that surfaces the instruction name, named accounts, and decoded args.What changed
presets::exponent_financeregistered undervisualsign-solana.exponent_finance.json) sourced from the published@exponent-labs/exponent-idlnpm package, which is the same data the Exponent SDK and orbmarkets explorer ship.decode_idl_data->parse_instruction_with_idl->build_named_accounts-> field builders, mirroring thedflow_aggregatorpreset.Dex("Exponent Finance"). Config matches all instructions for the program ID via("*", vec!["*"]).Two adaptations relative to the standard Anchor-style scaffold:
#[instruction(discriminator = [N])]attribute, so on-chain instruction discriminators are 1 byte rather than 8. The minimum-data-length check isdata.is_empty()and theidl_has_discriminatorstest only asserts!disc.is_empty(). The underlyingsolana_parser::find_instruction_by_discriminatoralready supports variable-length discriminators.Numbertype is a tuple-struct (a single anonymous[u64; 4]field).solana_parser'sIdlFieldschema requires named fields, so that one entry was rewritten in the JSON to{"name": "value", "type": {"array": ["u64", 4]}}. No other types or instructions were modified.Why this is safe
presets/mod.rs. Existing presets are unaffected. Programs that don't match the Exponent program ID continue to dispatch to their existing visualizer.parse_exponent_finance_instructionreturnsErr, and the visualizer falls through tobuild_fallback_fields(which still emits the raw hex). This matches thedflow_aggregatorpattern.NumberIDL patch is a structural rename only; the underlying type expression{"array": ["u64", 4]}is preserved, so any instruction that referencesNumberwill still decode the same bytes.Checks run (by agent)
cargo fmt -p visualsign-solanacargo clippy -p visualsign-solana --all-targets -- -D warnings-> cleancargo test -p visualsign-solana-> 70 unit tests pass (including the 4 newexponent_financetests: idl_loads, idl_has_discriminators, unknown_discriminator_returns_error, short_data_returns_error)make -C src test-> all workspace tests passmake -C src lint-> clean across all cratesManual steps needed (by human)
None - fully automated by CI.
How this is maintainable
dflow_aggregator, so a developer touching either picks up the pattern from one place. The two deviations (1-byte discriminator handling and theNumber-type rewrite) are documented inline by the test names and at the top of this PR.build.rsauto-discoversExponentFinanceVisualizerfrom the new directory, so adding/removing presets doesn't require touching a registry.@exponent-labs/exponent-idlpackage; refreshing the IDL is a copy-paste of a new release plus re-applying theNumber-field rewrite (the testtest_exponent_finance_idl_loadswill fail loudly if the rewrite is missed).unwrap_used = "deny", etc.) is enforced - the preset uses?andok_or/ok_or_elsefor all fallible paths.