From fc321372cdec945b8c259a351fbfdc9e67c95a1d Mon Sep 17 00:00:00 2001 From: abhinavgautam01 Date: Fri, 22 May 2026 09:38:20 +0530 Subject: [PATCH 1/3] fix(idl): avoid quoted string constant values --- lang/syn/src/idl/constant.rs | 22 +++++++++++++++++++++- tests/idl/idls/idl.json | 5 +++++ tests/idl/programs/idl/src/lib.rs | 3 +++ tests/idl/tests/idl.ts | 6 ++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/lang/syn/src/idl/constant.rs b/lang/syn/src/idl/constant.rs index 1bf00940ea..52f7c0a91f 100644 --- a/lang/syn/src/idl/constant.rs +++ b/lang/syn/src/idl/constant.rs @@ -22,6 +22,12 @@ pub fn gen_idl_print_fn_constant(item: &syn::ItemConst) -> TokenStream { _ => quote! { vec![] }, }; + let value = if is_string_type(&item.ty) { + quote! { #expr.to_string() } + } else { + quote! { format!("{:?}", #expr) } + }; + let fn_body = match gen_idl_type(&item.ty, &[]) { Ok((ty, _)) => gen_print_section( "const", @@ -30,7 +36,7 @@ pub fn gen_idl_print_fn_constant(item: &syn::ItemConst) -> TokenStream { name: #name.into(), docs: #docs, ty: #ty, - value: format!("{:?}", #expr), + value: #value, } }, ), @@ -44,3 +50,17 @@ pub fn gen_idl_print_fn_constant(item: &syn::ItemConst) -> TokenStream { } } } + +fn is_string_type(ty: &syn::Type) -> bool { + match ty { + syn::Type::Path(path) => { + path.path.segments.len() == 1 + && matches!( + path.path.segments.first().map(|segment| &segment.ident), + Some(ident) if ident == "String" || ident == "str" + ) + } + syn::Type::Reference(reference) => is_string_type(&reference.elem), + _ => false, + } +} diff --git a/tests/idl/idls/idl.json b/tests/idl/idls/idl.json index 28817c3826..3bb85cae50 100644 --- a/tests/idl/idls/idl.json +++ b/tests/idl/idls/idl.json @@ -1660,6 +1660,11 @@ "type": "i128", "value": "1000000" }, + { + "name": "SEED_PREFIX", + "type": "string", + "value": "favor" + }, { "name": "TEST_CONVERT_MODULE_PATHS", "docs": [ diff --git a/tests/idl/programs/idl/src/lib.rs b/tests/idl/programs/idl/src/lib.rs index e84252c0d1..0e94779d5b 100644 --- a/tests/idl/programs/idl/src/lib.rs +++ b/tests/idl/programs/idl/src/lib.rs @@ -15,6 +15,9 @@ pub const BYTE_STR: u8 = b't'; #[constant] pub const BYTES_STR: &[u8] = b"test"; +#[constant] +pub const SEED_PREFIX: &str = "favor"; + pub const NO_IDL: u16 = 55; #[program] diff --git a/tests/idl/tests/idl.ts b/tests/idl/tests/idl.ts index 914ebd8dcd..3a35e11324 100644 --- a/tests/idl/tests/idl.ts +++ b/tests/idl/tests/idl.ts @@ -606,6 +606,12 @@ describe("IDL", () => { c.type === "bytes" && c.value === "[116, 101, 115, 116]" ); + checkDefined( + (c) => + c.name === "seedPrefix" && + c.type === "string" && + c.value === "favor" + ); }); it("Does not include constants that are not marked with `#[constant]`", () => { From 6bf764dd242750596d6ea0c1c23c18237f21a340 Mon Sep 17 00:00:00 2001 From: abhinavgautam01 Date: Mon, 25 May 2026 20:10:10 +0530 Subject: [PATCH 2/3] test(idl): format string constant assertion --- tests/idl/tests/idl.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/idl/tests/idl.ts b/tests/idl/tests/idl.ts index 3a35e11324..6108462461 100644 --- a/tests/idl/tests/idl.ts +++ b/tests/idl/tests/idl.ts @@ -608,9 +608,7 @@ describe("IDL", () => { ); checkDefined( (c) => - c.name === "seedPrefix" && - c.type === "string" && - c.value === "favor" + c.name === "seedPrefix" && c.type === "string" && c.value === "favor" ); }); From d0bcada53ad140a6b9f92e13e23c9f55dbcd1155 Mon Sep 17 00:00:00 2001 From: abhinavgautam01 Date: Mon, 25 May 2026 20:30:57 +0530 Subject: [PATCH 3/3] test(events): handle transaction errors without logs --- cli/src/lib.rs | 54 ++++++++++++++++++++++++++++++++---- lang/syn/src/idl/constant.rs | 22 +-------------- tests/idl/idls/idl.json | 2 +- tests/idl/tests/idl.ts | 4 ++- 4 files changed, 53 insertions(+), 29 deletions(-) diff --git a/cli/src/lib.rs b/cli/src/lib.rs index f3ae60012b..7a19ec4a73 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -3334,6 +3334,7 @@ fn idl_ts(idl: &Idl) -> Result { let idl_name = &idl.metadata.name; let type_name = idl_name.to_pascal_case(); let mut camel_idl = serde_json::to_value(idl)?; + normalize_string_const_values_for_ts(&mut camel_idl); camel_case_idl_identifiers(&mut camel_idl); let camel_idl = serde_json::to_string_pretty(&serde_json::from_value::(camel_idl)?)?; @@ -3349,6 +3350,37 @@ export type {type_name} = {camel_idl}; )) } +fn normalize_string_const_values_for_ts(idl: &mut JsonValue) { + let Some(constants) = idl.get_mut("constants").and_then(JsonValue::as_array_mut) else { + return; + }; + + for constant in constants { + let Some(constant) = constant.as_object_mut() else { + continue; + }; + + if !matches!( + constant.get("type").and_then(JsonValue::as_str), + Some("string") + ) { + continue; + } + + let Some(value) = constant.get_mut("value") else { + continue; + }; + + let Some(value_str) = value.as_str() else { + continue; + }; + + if let Ok(parsed_value) = serde_json::from_str::(value_str) { + *value = JsonValue::String(parsed_value); + } + } +} + fn camel_case_idl_identifiers(value: &mut JsonValue) { match value { JsonValue::Array(values) => { @@ -6788,12 +6820,20 @@ mod tests { }, }, }], - constants: vec![anchor_lang_idl::types::IdlConst { - name: "seed_prefix".to_string(), - docs: Vec::new(), - ty: IdlType::String, - value: "SEED_PREFIX".to_string(), - }], + constants: vec![ + anchor_lang_idl::types::IdlConst { + name: "seed_prefix".to_string(), + docs: Vec::new(), + ty: IdlType::String, + value: "SEED_PREFIX".to_string(), + }, + anchor_lang_idl::types::IdlConst { + name: "literal_seed".to_string(), + docs: Vec::new(), + ty: IdlType::String, + value: "\"favor\"".to_string(), + }, + ], }; let ts = idl_ts(&idl).unwrap(); @@ -6813,6 +6853,8 @@ mod tests { assert!(ts.contains(r#""generic": "itemType""#)); assert!(ts.contains(r#""name": "seedPrefix""#)); assert!(ts.contains(r#""value": "SEED_PREFIX""#)); + assert!(ts.contains(r#""name": "literalSeed""#)); + assert!(ts.contains(r#""value": "favor""#)); } #[test] diff --git a/lang/syn/src/idl/constant.rs b/lang/syn/src/idl/constant.rs index 52f7c0a91f..1bf00940ea 100644 --- a/lang/syn/src/idl/constant.rs +++ b/lang/syn/src/idl/constant.rs @@ -22,12 +22,6 @@ pub fn gen_idl_print_fn_constant(item: &syn::ItemConst) -> TokenStream { _ => quote! { vec![] }, }; - let value = if is_string_type(&item.ty) { - quote! { #expr.to_string() } - } else { - quote! { format!("{:?}", #expr) } - }; - let fn_body = match gen_idl_type(&item.ty, &[]) { Ok((ty, _)) => gen_print_section( "const", @@ -36,7 +30,7 @@ pub fn gen_idl_print_fn_constant(item: &syn::ItemConst) -> TokenStream { name: #name.into(), docs: #docs, ty: #ty, - value: #value, + value: format!("{:?}", #expr), } }, ), @@ -50,17 +44,3 @@ pub fn gen_idl_print_fn_constant(item: &syn::ItemConst) -> TokenStream { } } } - -fn is_string_type(ty: &syn::Type) -> bool { - match ty { - syn::Type::Path(path) => { - path.path.segments.len() == 1 - && matches!( - path.path.segments.first().map(|segment| &segment.ident), - Some(ident) if ident == "String" || ident == "str" - ) - } - syn::Type::Reference(reference) => is_string_type(&reference.elem), - _ => false, - } -} diff --git a/tests/idl/idls/idl.json b/tests/idl/idls/idl.json index 3bb85cae50..f5247cf47a 100644 --- a/tests/idl/idls/idl.json +++ b/tests/idl/idls/idl.json @@ -1663,7 +1663,7 @@ { "name": "SEED_PREFIX", "type": "string", - "value": "favor" + "value": "\"favor\"" }, { "name": "TEST_CONVERT_MODULE_PATHS", diff --git a/tests/idl/tests/idl.ts b/tests/idl/tests/idl.ts index 6108462461..f84e7e3254 100644 --- a/tests/idl/tests/idl.ts +++ b/tests/idl/tests/idl.ts @@ -608,7 +608,9 @@ describe("IDL", () => { ); checkDefined( (c) => - c.name === "seedPrefix" && c.type === "string" && c.value === "favor" + c.name === "seedPrefix" && + c.type === "string" && + c.value === '"favor"' ); });