Background
While reviewing #375 (which adds core::arg_rendering::format_arg_value — a shared, charset-safe, type-aware arg renderer used by the new Marginfi preset), I checked how the 17 existing IDL-based presets currently render instruction args. None of them use a shared helper — each has its own local, copy-pasted format_arg_value:
// e.g. kamino_vault, meteora_dlmm, onre_app, kamino_farms, kamino_limit, meteora_damm_v2
fn format_arg_value(value: &serde_json::Value) -> String {
match value {
serde_json::Value::String(s) => s.clone(),
other => other.to_string(),
}
}
// e.g. jupiter_perps, kamino_borrow, drift, jupiter_earn, squads_multisig,
// exponent_finance, neutral_trade, jupiter_borrow, orca_whirlpool
fn format_arg_value(value: &serde_json::Value) -> String {
match value {
serde_json::Value::String(s) => s.clone(),
serde_json::Value::Number(n) => n.to_string(),
serde_json::Value::Bool(b) => b.to_string(),
serde_json::Value::Null => "null".to_string(),
other => other.to_string(),
}
}
Presets: kamino_vault, jupiter_perps, kamino_borrow, meteora_dlmm, drift, onre_app, jupiter_earn, kamino_farms, squads_multisig, kamino_limit, exponent_finance, meteora_damm_v2, neutral_trade, metadao_conditional_vault, jupiter_borrow, orca_whirlpool, metadao_futarchy.
The problem
For any arg whose serde_json::Value is an Array or Object (byte arrays, structs, enum payloads, nested IDL types), the fallback arm calls other.to_string() / value.to_string(), which is serde_json::Value's Display impl — i.e. it serializes the value as literal JSON, quotes and all (e.g. ["a","b"], {"side":"buy"}).
That's a charset-safety violation risk: SignablePayload::validate_charset rejects " and \ in rendered field text. Any preset among the 17 above that decodes an instruction with an array- or struct-typed arg would emit a fallback string containing ", which the crate's own charset validation is specifically designed to catch and reject — meaning either (a) it's never been hit because none of the fuzzed/tested transactions for these presets exercise an array/struct arg, or (b) it's silently failing charset validation somewhere already. Either way it's a live gap, not a hypothetical one, since it doesn't depend on any future IDL — it's live in main today for these 17 presets.
Suggested fix
Migrate these presets off their local format_arg_value onto the shared, charset-safe, type-aware version added in core::arg_rendering by #375 (plus the find_idl_instruction/arg_types_for helpers proposed as a follow-up there). This fixes the charset-safety gap and gets type-driven byte-array rendering (no more mis-rendering an array of small numbers as a JSON blob) in one pass, rather than fixing each preset's local copy separately.
Scope note
Deliberately kept out of #375 itself — that PR's own description says "existing presets keep their current renderers untouched," and this touches ~17 files rather than the one new preset. Tracking here so it doesn't get lost.
Background
While reviewing #375 (which adds
core::arg_rendering::format_arg_value— a shared, charset-safe, type-aware arg renderer used by the new Marginfi preset), I checked how the 17 existing IDL-based presets currently render instruction args. None of them use a shared helper — each has its own local, copy-pastedformat_arg_value:Presets:
kamino_vault,jupiter_perps,kamino_borrow,meteora_dlmm,drift,onre_app,jupiter_earn,kamino_farms,squads_multisig,kamino_limit,exponent_finance,meteora_damm_v2,neutral_trade,metadao_conditional_vault,jupiter_borrow,orca_whirlpool,metadao_futarchy.The problem
For any arg whose
serde_json::Valueis anArrayorObject(byte arrays, structs, enum payloads, nested IDL types), the fallback arm callsother.to_string()/value.to_string(), which isserde_json::Value'sDisplayimpl — i.e. it serializes the value as literal JSON, quotes and all (e.g.["a","b"],{"side":"buy"}).That's a charset-safety violation risk:
SignablePayload::validate_charsetrejects"and\in rendered field text. Any preset among the 17 above that decodes an instruction with an array- or struct-typed arg would emit a fallback string containing", which the crate's own charset validation is specifically designed to catch and reject — meaning either (a) it's never been hit because none of the fuzzed/tested transactions for these presets exercise an array/struct arg, or (b) it's silently failing charset validation somewhere already. Either way it's a live gap, not a hypothetical one, since it doesn't depend on any future IDL — it's live inmaintoday for these 17 presets.Suggested fix
Migrate these presets off their local
format_arg_valueonto the shared, charset-safe, type-aware version added incore::arg_renderingby #375 (plus thefind_idl_instruction/arg_types_forhelpers proposed as a follow-up there). This fixes the charset-safety gap and gets type-driven byte-array rendering (no more mis-rendering an array of small numbers as a JSON blob) in one pass, rather than fixing each preset's local copy separately.Scope note
Deliberately kept out of #375 itself — that PR's own description says "existing presets keep their current renderers untouched," and this touches ~17 files rather than the one new preset. Tracking here so it doesn't get lost.