From ba94bbdc9bbb0496acbca23c6ba6fad94ab2d3c9 Mon Sep 17 00:00:00 2001 From: sofia-bobbiesi Date: Mon, 2 Mar 2026 15:19:57 -0300 Subject: [PATCH 1/3] feat: add AnyData type support across the Tx3 language components --- bin/tx3c/src/tii/mod.rs | 1 + crates/tx3-lang/src/analyzing.rs | 17 +++++++++++++++++ crates/tx3-lang/src/ast.rs | 2 ++ crates/tx3-lang/src/lowering.rs | 1 + crates/tx3-lang/src/parsing.rs | 3 +++ crates/tx3-lang/src/tx3.pest | 1 + crates/tx3-tir/src/model/core.rs | 1 + 7 files changed, 26 insertions(+) diff --git a/bin/tx3c/src/tii/mod.rs b/bin/tx3c/src/tii/mod.rs index 0c28b20e..2a04adc3 100644 --- a/bin/tx3c/src/tii/mod.rs +++ b/bin/tx3c/src/tii/mod.rs @@ -20,6 +20,7 @@ pub fn map_ast_type_to_json_schema(r#type: &tx3_lang::ast::Type) -> Value { tx3_lang::ast::Type::Bytes => { json!({ "$ref": "https://tx3.land/specs/v1beta0/core#Bytes" }) } + tx3_lang::ast::Type::AnyData => json!({}), tx3_lang::ast::Type::Address => { json!({ "$ref": "https://tx3.land/specs/v1beta0/core#Address" }) } diff --git a/crates/tx3-lang/src/analyzing.rs b/crates/tx3-lang/src/analyzing.rs index 55e50b02..4fcc5252 100644 --- a/crates/tx3-lang/src/analyzing.rs +++ b/crates/tx3-lang/src/analyzing.rs @@ -1537,6 +1537,23 @@ mod tests { assert!(result.errors.is_empty()); } + #[test] + fn test_record_field_any_data_type_success() { + let mut ast = crate::parsing::parse_string( + r#" + type MyRecord { + field1: Int, + field2: AnyData, + } + "#, + ) + .unwrap(); + + let result = analyze(&mut ast); + + assert!(result.errors.is_empty()); + } + #[test] fn test_min_utxo_undefined_output_error() { let mut ast = crate::parsing::parse_string( diff --git a/crates/tx3-lang/src/ast.rs b/crates/tx3-lang/src/ast.rs index 54578928..28d44337 100644 --- a/crates/tx3-lang/src/ast.rs +++ b/crates/tx3-lang/src/ast.rs @@ -809,6 +809,7 @@ pub enum Type { Int, Bool, Bytes, + AnyData, Address, Utxo, UtxoRef, @@ -826,6 +827,7 @@ impl std::fmt::Display for Type { Type::Int => write!(f, "Int"), Type::Bool => write!(f, "Bool"), Type::Bytes => write!(f, "Bytes"), + Type::AnyData => write!(f, "AnyData"), Type::Address => write!(f, "Address"), Type::UtxoRef => write!(f, "UtxoRef"), Type::AnyAsset => write!(f, "AnyAsset"), diff --git a/crates/tx3-lang/src/lowering.rs b/crates/tx3-lang/src/lowering.rs index a49dfe79..288b41c6 100644 --- a/crates/tx3-lang/src/lowering.rs +++ b/crates/tx3-lang/src/lowering.rs @@ -344,6 +344,7 @@ impl IntoLower for ast::Type { ast::Type::Int => Ok(Type::Int), ast::Type::Bool => Ok(Type::Bool), ast::Type::Bytes => Ok(Type::Bytes), + ast::Type::AnyData => Ok(Type::AnyData), ast::Type::Address => Ok(Type::Address), ast::Type::Utxo => Ok(Type::Utxo), ast::Type::UtxoRef => Ok(Type::UtxoRef), diff --git a/crates/tx3-lang/src/parsing.rs b/crates/tx3-lang/src/parsing.rs index 2b34fc1c..11c01b54 100644 --- a/crates/tx3-lang/src/parsing.rs +++ b/crates/tx3-lang/src/parsing.rs @@ -1288,6 +1288,7 @@ impl AstNode for Type { "Int" => Ok(Type::Int), "Bool" => Ok(Type::Bool), "Bytes" => Ok(Type::Bytes), + "AnyData" => Ok(Type::AnyData), "Address" => Ok(Type::Address), "UtxoRef" => Ok(Type::UtxoRef), "AnyAsset" => Ok(Type::AnyAsset), @@ -1575,6 +1576,8 @@ mod tests { input_to_ast_check!(Type, "bytes", "Bytes", Type::Bytes); + input_to_ast_check!(Type, "any_data", "AnyData", Type::AnyData); + input_to_ast_check!(Type, "address", "Address", Type::Address); input_to_ast_check!(Type, "utxo_ref", "UtxoRef", Type::UtxoRef); diff --git a/crates/tx3-lang/src/tx3.pest b/crates/tx3-lang/src/tx3.pest index a01471ff..13be9645 100644 --- a/crates/tx3-lang/src/tx3.pest +++ b/crates/tx3-lang/src/tx3.pest @@ -18,6 +18,7 @@ primitive_type = { "Bool" | "Bytes" | "AnyAsset" | + "AnyData" | "Address" | "UtxoRef" } diff --git a/crates/tx3-tir/src/model/core.rs b/crates/tx3-tir/src/model/core.rs index a30896d2..1b02d0ec 100644 --- a/crates/tx3-tir/src/model/core.rs +++ b/crates/tx3-tir/src/model/core.rs @@ -57,6 +57,7 @@ pub enum Type { Int, Bool, Bytes, + AnyData, Address, Utxo, UtxoRef, From ab8a211fcbf2196b5527faf0facfb0cd68733a12 Mon Sep 17 00:00:00 2001 From: sofia-bobbiesi Date: Tue, 3 Mar 2026 15:46:10 -0300 Subject: [PATCH 2/3] feat: add support for Data variant in ArgValue --- crates/tx3-tir/src/reduce/mod.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/crates/tx3-tir/src/reduce/mod.rs b/crates/tx3-tir/src/reduce/mod.rs index eb60cf4c..a03fb538 100644 --- a/crates/tx3-tir/src/reduce/mod.rs +++ b/crates/tx3-tir/src/reduce/mod.rs @@ -300,6 +300,7 @@ fn arg_value_into_expr(arg: ArgValue) -> Expression { ArgValue::Bool(x) => Expression::Bool(x), ArgValue::String(x) => Expression::String(x), ArgValue::Bytes(x) => Expression::Bytes(x), + ArgValue::Data(x) => x, ArgValue::UtxoSet(x) => Expression::UtxoSet(x), ArgValue::UtxoRef(x) => Expression::UtxoRefs(vec![x]), } @@ -1386,17 +1387,17 @@ impl Apply for Tx { fn reduce(self) -> Result { Ok(Self { - references: self.references.reduce()?, - inputs: self.inputs.reduce()?, - outputs: self.outputs.reduce()?, - validity: self.validity.reduce()?, - mints: self.mints.reduce()?, - burns: self.burns.reduce()?, - fees: self.fees.reduce()?, - adhoc: self.adhoc.reduce()?, - collateral: self.collateral.reduce()?, - signers: self.signers.reduce()?, - metadata: self.metadata.reduce()?, + references: Apply::reduce(self.references)?, + inputs: Apply::reduce(self.inputs)?, + outputs: Apply::reduce(self.outputs)?, + validity: Apply::reduce(self.validity)?, + mints: Apply::reduce(self.mints)?, + burns: Apply::reduce(self.burns)?, + fees: Apply::reduce(self.fees)?, + adhoc: Apply::reduce(self.adhoc)?, + collateral: Apply::reduce(self.collateral)?, + signers: Apply::reduce(self.signers)?, + metadata: Apply::reduce(self.metadata)?, }) } } @@ -1408,6 +1409,7 @@ pub enum ArgValue { String(String), Bytes(Vec), Address(Vec), + Data(Expression), UtxoSet(UtxoSet), UtxoRef(UtxoRef), } From e0ed870906b8ecc203ad864fb81931b35d3ebac0 Mon Sep 17 00:00:00 2001 From: sofia-bobbiesi Date: Wed, 4 Mar 2026 20:05:49 -0300 Subject: [PATCH 3/3] feat: add value_to_data_expr function and support for AnyData type in from_json --- crates/tx3-resolver/src/interop.rs | 42 ++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/crates/tx3-resolver/src/interop.rs b/crates/tx3-resolver/src/interop.rs index 26320139..18ca30f2 100644 --- a/crates/tx3-resolver/src/interop.rs +++ b/crates/tx3-resolver/src/interop.rs @@ -4,6 +4,7 @@ use serde_json::{Number, Value}; use thiserror::Error; use tx3_tir::model::core::{Type, UtxoRef}; +use tx3_tir::model::v1beta0::Expression; pub use tx3_tir::reduce::ArgValue; #[derive(Debug, Error)] @@ -188,7 +189,7 @@ fn value_to_address(value: Value) -> Result, Error> { Ok(out) } -fn value_to_underfined(value: Value) -> Result { +fn value_to_undefined(value: Value) -> Result { match value { Value::Bool(b) => Ok(ArgValue::Bool(b)), Value::Number(x) => Ok(ArgValue::Int(number_to_bigint(x)?)), @@ -197,6 +198,26 @@ fn value_to_underfined(value: Value) -> Result { } } +fn value_to_data_expr(value: Value) -> Result { + match value { + Value::Null => Ok(Expression::None), + Value::Bool(b) => Ok(Expression::Bool(b)), + Value::Number(n) => Ok(Expression::Number(number_to_bigint(n)?)), + Value::String(s) => Ok(Expression::String(s)), + Value::Array(items) => Ok(Expression::List( + items + .into_iter() + .map(value_to_data_expr) + .collect::, _>>()?, + )), + Value::Object(map) => Ok(Expression::Map( + map.into_iter() + .map(|(key, value)| Ok((Expression::String(key), value_to_data_expr(value)?))) + .collect::, Error>>()?, + )), + } +} + fn string_to_utxo_ref(s: &str) -> Result { let (txid, index) = s .split_once('#') @@ -239,7 +260,11 @@ pub fn from_json(value: Value, target: &Type) -> Result { let x = value_to_utxo_ref(value)?; Ok(ArgValue::UtxoRef(x)) } - Type::Undefined => value_to_underfined(value), + Type::AnyData => { + let x = value_to_data_expr(value)?; + Ok(ArgValue::Data(x)) + } + Type::Undefined => value_to_undefined(value), x => Err(Error::TargetTypeNotSupported(x.clone())), } } @@ -280,6 +305,10 @@ mod tests { ArgValue::UtxoRef(b) => utxo_ref == b, _ => false, }, + ArgValue::Data(a) => match b { + ArgValue::Data(b) => a == b, + _ => false, + }, } } @@ -403,4 +432,13 @@ mod tests { json_to_value_test(json, Type::UtxoRef, ArgValue::UtxoRef(utxo_ref)); } + + #[test] + fn test_round_trip_any_data_bool() { + json_to_value_test( + json!(true), + Type::AnyData, + ArgValue::Data(Expression::Bool(true)), + ); + } }