Skip to content

Commit 1be959c

Browse files
committed
refactor: add native struct support to abi crate; refine abi handling in app client; more tests
1 parent 6d27d07 commit 1be959c

File tree

13 files changed

+1279
-527
lines changed

13 files changed

+1279
-527
lines changed

crates/algokit_abi/src/abi_type.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::{
55
STATIC_ARRAY_REGEX, UFIXED_REGEX,
66
},
77
types::collections::tuple::find_bool_sequence_end,
8+
types::struct_type::StructType,
89
};
910
use std::{
1011
fmt::{Display, Formatter, Result as FmtResult},
@@ -98,6 +99,8 @@ pub enum ABIType {
9899
StaticArray(Box<ABIType>, usize),
99100
/// A dynamic-length array of another ABI type.
100101
DynamicArray(Box<ABIType>),
102+
/// A named struct type with ordered fields
103+
Struct(StructType),
101104
}
102105

103106
impl AsRef<ABIType> for ABIType {
@@ -125,6 +128,24 @@ impl ABIType {
125128
ABIType::String => self.encode_string(value),
126129
ABIType::Byte => self.encode_byte(value),
127130
ABIType::Bool => self.encode_bool(value),
131+
ABIType::Struct(struct_type) => {
132+
// Convert struct map -> tuple vec based on field order, encode with tuple encoder
133+
let tuple_type = struct_type.to_tuple_type();
134+
let tuple_values = match value {
135+
ABIValue::Struct(map) => struct_type.struct_to_tuple(map)?,
136+
// Backwards-compatible: allow tuple-style array values for struct-typed args
137+
ABIValue::Array(values) => values.clone(),
138+
_ => {
139+
return Err(ABIError::EncodingError {
140+
message: format!(
141+
"ABI value mismatch, expected struct for type {}, got {:?}",
142+
self, value
143+
),
144+
});
145+
}
146+
};
147+
tuple_type.encode(&ABIValue::Array(tuple_values))
148+
}
128149
}
129150
}
130151

@@ -146,13 +167,30 @@ impl ABIType {
146167
ABIType::Tuple(_) => self.decode_tuple(bytes),
147168
ABIType::StaticArray(_, _size) => self.decode_static_array(bytes),
148169
ABIType::DynamicArray(_) => self.decode_dynamic_array(bytes),
170+
ABIType::Struct(struct_type) => {
171+
let tuple_type = struct_type.to_tuple_type();
172+
let decoded = tuple_type.decode(bytes)?;
173+
match decoded {
174+
ABIValue::Array(values) => {
175+
let map = struct_type.tuple_to_struct(values)?;
176+
Ok(ABIValue::Struct(map))
177+
}
178+
other => Err(ABIError::DecodingError {
179+
message: format!(
180+
"Expected tuple decode for struct {}, got {:?}",
181+
struct_type.name, other
182+
),
183+
}),
184+
}
185+
}
149186
}
150187
}
151188

152189
pub(crate) fn is_dynamic(&self) -> bool {
153190
match self {
154191
ABIType::StaticArray(child_type, _) => child_type.is_dynamic(),
155192
ABIType::Tuple(child_types) => child_types.iter().any(|t| t.is_dynamic()),
193+
ABIType::Struct(struct_type) => struct_type.to_tuple_type().as_ref().is_dynamic(),
156194
ABIType::DynamicArray(_) | ABIType::String => true,
157195
_ => false,
158196
}
@@ -190,6 +228,7 @@ impl ABIType {
190228
}
191229
Ok(size)
192230
}
231+
ABIType::Struct(struct_type) => Self::get_size(&struct_type.to_tuple_type()),
193232
ABIType::String => Err(ABIError::DecodingError {
194233
message: format!("Failed to get size, {} is a dynamic type", abi_type),
195234
}),
@@ -221,6 +260,9 @@ impl Display for ABIType {
221260
ABIType::DynamicArray(child_type) => {
222261
write!(f, "{}[]", child_type)
223262
}
263+
ABIType::Struct(struct_type) => {
264+
write!(f, "{}", struct_type.to_tuple_type())
265+
}
224266
}
225267
}
226268
}

crates/algokit_abi/src/abi_value.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use num_bigint::BigUint;
2+
use std::collections::HashMap;
23

34
/// Represents a value that can be encoded or decoded as an ABI type.
45
#[derive(Debug, Clone, PartialEq)]
@@ -15,6 +16,8 @@ pub enum ABIValue {
1516
Array(Vec<ABIValue>),
1617
/// An Algorand address.
1718
Address(String),
19+
/// A struct value represented as a map of field name to value.
20+
Struct(HashMap<String, ABIValue>),
1821
}
1922

2023
impl From<bool> for ABIValue {

0 commit comments

Comments
 (0)