glin_contracts/
encoding.rs

1// SCALE encoding/decoding for contract arguments
2
3use anyhow::{Context, Result};
4use ink_metadata::InkProject;
5use scale::{Decode, Encode};
6use scale_info::{form::PortableForm, TypeDef, TypeDefPrimitive};
7use serde_json::Value as JsonValue;
8use subxt::utils::AccountId32;
9
10// Type aliases for PortableForm specs
11type MessageParamSpec = ink_metadata::MessageParamSpec<PortableForm>;
12type TypeSpec = ink_metadata::TypeSpec<PortableForm>;
13
14/// Encode contract arguments based on their types from metadata
15pub fn encode_args(
16    args: &[String],
17    param_specs: &[MessageParamSpec],
18    metadata: &InkProject,
19) -> Result<Vec<u8>> {
20    if args.len() != param_specs.len() {
21        anyhow::bail!(
22            "Argument count mismatch: expected {}, got {}",
23            param_specs.len(),
24            args.len()
25        );
26    }
27
28    let mut encoded = Vec::new();
29
30    for (arg_str, param) in args.iter().zip(param_specs.iter()) {
31        // Get type ID from param
32        let type_id = param.ty().ty().id;
33        let arg_bytes = encode_value_by_id(arg_str, type_id, metadata)?;
34        encoded.extend_from_slice(&arg_bytes);
35    }
36
37    Ok(encoded)
38}
39
40/// Encode a single value based on its type ID
41fn encode_value_by_id(value_str: &str, type_id: u32, metadata: &InkProject) -> Result<Vec<u8>> {
42    let registry = metadata.registry();
43
44    let ty = registry
45        .resolve(type_id)
46        .ok_or_else(|| anyhow::anyhow!("Type {} not found in registry", type_id))?;
47
48    // Access type_def field directly (not deprecated)
49    match &ty.type_def {
50        TypeDef::Primitive(prim) => encode_primitive(value_str, prim),
51        TypeDef::Composite(_) => encode_composite(value_str, type_id, metadata),
52        TypeDef::Variant(_) => encode_variant(value_str, type_id, metadata),
53        TypeDef::Sequence(_) => encode_sequence(value_str, type_id, metadata),
54        TypeDef::Array(_) => encode_array(value_str, type_id, metadata),
55        TypeDef::Tuple(_) => encode_tuple(value_str, type_id, metadata),
56        TypeDef::Compact(_) => {
57            // Compact encoding - parse as number and use compact encoding
58            let num: u128 = value_str
59                .parse()
60                .context("Failed to parse compact value as number")?;
61            Ok(scale::Compact(num).encode())
62        }
63        TypeDef::BitSequence(_) => {
64            anyhow::bail!("BitSequence encoding not yet supported")
65        }
66    }
67}
68
69/// Encode primitive types
70fn encode_primitive(value_str: &str, prim: &TypeDefPrimitive) -> Result<Vec<u8>> {
71    match prim {
72        TypeDefPrimitive::Bool => {
73            let val: bool = value_str.parse().context("Failed to parse boolean")?;
74            Ok(val.encode())
75        }
76        TypeDefPrimitive::Char => {
77            let val: char = value_str
78                .chars()
79                .next()
80                .ok_or_else(|| anyhow::anyhow!("Empty char value"))?;
81            Ok((val as u32).encode())
82        }
83        TypeDefPrimitive::Str => Ok(value_str.to_string().encode()),
84        TypeDefPrimitive::U8 => {
85            let val: u8 = value_str.parse()?;
86            Ok(val.encode())
87        }
88        TypeDefPrimitive::U16 => {
89            let val: u16 = value_str.parse()?;
90            Ok(val.encode())
91        }
92        TypeDefPrimitive::U32 => {
93            let val: u32 = value_str.parse()?;
94            Ok(val.encode())
95        }
96        TypeDefPrimitive::U64 => {
97            let val: u64 = value_str.parse()?;
98            Ok(val.encode())
99        }
100        TypeDefPrimitive::U128 => {
101            let val: u128 = value_str.parse()?;
102            Ok(val.encode())
103        }
104        TypeDefPrimitive::U256 => {
105            anyhow::bail!("U256 encoding not yet supported")
106        }
107        TypeDefPrimitive::I8 => {
108            let val: i8 = value_str.parse()?;
109            Ok(val.encode())
110        }
111        TypeDefPrimitive::I16 => {
112            let val: i16 = value_str.parse()?;
113            Ok(val.encode())
114        }
115        TypeDefPrimitive::I32 => {
116            let val: i32 = value_str.parse()?;
117            Ok(val.encode())
118        }
119        TypeDefPrimitive::I64 => {
120            let val: i64 = value_str.parse()?;
121            Ok(val.encode())
122        }
123        TypeDefPrimitive::I128 => {
124            let val: i128 = value_str.parse()?;
125            Ok(val.encode())
126        }
127        TypeDefPrimitive::I256 => {
128            anyhow::bail!("I256 encoding not yet supported")
129        }
130    }
131}
132
133/// Encode composite types (structs)
134fn encode_composite(value_str: &str, type_id: u32, metadata: &InkProject) -> Result<Vec<u8>> {
135    let registry = metadata.registry();
136    let ty = registry
137        .resolve(type_id)
138        .ok_or_else(|| anyhow::anyhow!("Type {} not found", type_id))?;
139
140    // Check if this is an AccountId or AccountId32 (special case)
141    let last_segment = ty.path.segments.last().map(|s| s.as_str());
142    if last_segment == Some("AccountId32") || last_segment == Some("AccountId") {
143        return encode_account_id(value_str);
144    }
145
146    // Try to parse as JSON for complex types
147    let json: JsonValue =
148        serde_json::from_str(value_str).context("Failed to parse composite value as JSON")?;
149
150    if let TypeDef::Composite(composite) = &ty.type_def {
151        let mut encoded = Vec::new();
152
153        for field in &composite.fields {
154            let field_name = field
155                .name
156                .as_ref()
157                .ok_or_else(|| anyhow::anyhow!("Unnamed field in composite"))?;
158
159            let field_value = json
160                .get(field_name)
161                .ok_or_else(|| anyhow::anyhow!("Missing field: {}", field_name))?
162                .to_string();
163
164            let field_type_id = field.ty.id;
165            let field_bytes = encode_value_by_id(&field_value, field_type_id, metadata)?;
166            encoded.extend_from_slice(&field_bytes);
167        }
168
169        Ok(encoded)
170    } else {
171        anyhow::bail!("Expected composite type")
172    }
173}
174
175/// Encode AccountId32
176fn encode_account_id(value_str: &str) -> Result<Vec<u8>> {
177    use std::str::FromStr;
178
179    // Try parsing as SS58 address
180    if let Ok(account_id) = AccountId32::from_str(value_str) {
181        return Ok(account_id.0.encode());
182    }
183
184    // Try parsing as hex
185    if value_str.starts_with("0x") {
186        let bytes =
187            hex::decode(value_str.trim_start_matches("0x")).context("Invalid hex address")?;
188        if bytes.len() == 32 {
189            return Ok(bytes);
190        }
191    }
192
193    anyhow::bail!("Invalid AccountId32 format: {}", value_str)
194}
195
196/// Encode variant types (enums, Option, Result)
197fn encode_variant(value_str: &str, type_id: u32, metadata: &InkProject) -> Result<Vec<u8>> {
198    let registry = metadata.registry();
199    let ty = registry
200        .resolve(type_id)
201        .ok_or_else(|| anyhow::anyhow!("Type {} not found", type_id))?;
202
203    // Check for common types: Option, Result
204    let type_name = ty.path.segments.last().map(|s| s.as_str());
205
206    match type_name {
207        Some("Option") => encode_option(value_str, type_id, metadata),
208        Some("Result") => encode_result(value_str, type_id, metadata),
209        _ => {
210            // Generic enum
211            let json: JsonValue =
212                serde_json::from_str(value_str).context("Failed to parse variant as JSON")?;
213
214            if let Some(variant_name) = json.get("variant").and_then(|v| v.as_str()) {
215                if let TypeDef::Variant(variant_def) = &ty.type_def {
216                    let variant = variant_def
217                        .variants
218                        .iter()
219                        .find(|v| v.name == variant_name)
220                        .ok_or_else(|| anyhow::anyhow!("Variant {} not found", variant_name))?;
221
222                    let mut encoded = Vec::new();
223                    encoded.push(variant.index);
224
225                    // Encode variant fields if any
226                    if let Some(fields_json) = json.get("fields") {
227                        for (i, field) in variant.fields.iter().enumerate() {
228                            let field_value = fields_json
229                                .get(i)
230                                .ok_or_else(|| anyhow::anyhow!("Missing variant field {}", i))?
231                                .to_string();
232
233                            let field_type_id = field.ty.id;
234                            let field_bytes =
235                                encode_value_by_id(&field_value, field_type_id, metadata)?;
236                            encoded.extend_from_slice(&field_bytes);
237                        }
238                    }
239
240                    return Ok(encoded);
241                }
242            }
243
244            anyhow::bail!("Invalid variant encoding")
245        }
246    }
247}
248
249/// Encode Option type
250fn encode_option(value_str: &str, _type_id: u32, _metadata: &InkProject) -> Result<Vec<u8>> {
251    if value_str == "null" || value_str.is_empty() {
252        // None variant (index 0)
253        Ok(vec![0u8])
254    } else {
255        // Some variant (index 1) + encoded value
256        let mut encoded = vec![1u8];
257        encoded.extend_from_slice(&value_str.to_string().encode());
258        Ok(encoded)
259    }
260}
261
262/// Encode Result type
263fn encode_result(value_str: &str, _type_id: u32, _metadata: &InkProject) -> Result<Vec<u8>> {
264    let json: JsonValue =
265        serde_json::from_str(value_str).context("Failed to parse Result as JSON")?;
266
267    if json.get("Ok").is_some() {
268        // Ok variant (index 0)
269        let mut encoded = vec![0u8];
270        let ok_value = json.get("Ok").unwrap().to_string();
271        encoded.extend_from_slice(&ok_value.encode());
272        Ok(encoded)
273    } else if json.get("Err").is_some() {
274        // Err variant (index 1)
275        let mut encoded = vec![1u8];
276        let err_value = json.get("Err").unwrap().to_string();
277        encoded.extend_from_slice(&err_value.encode());
278        Ok(encoded)
279    } else {
280        anyhow::bail!("Invalid Result format")
281    }
282}
283
284/// Encode sequence (Vec)
285fn encode_sequence(value_str: &str, type_id: u32, metadata: &InkProject) -> Result<Vec<u8>> {
286    let json: JsonValue =
287        serde_json::from_str(value_str).context("Failed to parse sequence as JSON array")?;
288
289    let array = json
290        .as_array()
291        .ok_or_else(|| anyhow::anyhow!("Expected JSON array"))?;
292
293    let registry = metadata.registry();
294    let ty = registry
295        .resolve(type_id)
296        .ok_or_else(|| anyhow::anyhow!("Type {} not found", type_id))?;
297
298    if let TypeDef::Sequence(seq) = &ty.type_def {
299        let element_type_id = seq.type_param.id;
300
301        // Encode length as compact
302        let mut encoded = scale::Compact(array.len() as u32).encode();
303
304        // Encode each element
305        for element in array {
306            let element_str = element.to_string();
307            let element_bytes = encode_value_by_id(&element_str, element_type_id, metadata)?;
308            encoded.extend_from_slice(&element_bytes);
309        }
310
311        Ok(encoded)
312    } else {
313        anyhow::bail!("Expected sequence type")
314    }
315}
316
317/// Encode array
318fn encode_array(value_str: &str, type_id: u32, metadata: &InkProject) -> Result<Vec<u8>> {
319    let json: JsonValue =
320        serde_json::from_str(value_str).context("Failed to parse array as JSON")?;
321
322    let array = json
323        .as_array()
324        .ok_or_else(|| anyhow::anyhow!("Expected JSON array"))?;
325
326    let registry = metadata.registry();
327    let ty = registry
328        .resolve(type_id)
329        .ok_or_else(|| anyhow::anyhow!("Type {} not found", type_id))?;
330
331    if let TypeDef::Array(arr_def) = &ty.type_def {
332        let element_type_id = arr_def.type_param.id;
333
334        if array.len() != arr_def.len as usize {
335            anyhow::bail!(
336                "Array length mismatch: expected {}, got {}",
337                arr_def.len,
338                array.len()
339            );
340        }
341
342        let mut encoded = Vec::new();
343
344        for element in array {
345            let element_str = element.to_string();
346            let element_bytes = encode_value_by_id(&element_str, element_type_id, metadata)?;
347            encoded.extend_from_slice(&element_bytes);
348        }
349
350        Ok(encoded)
351    } else {
352        anyhow::bail!("Expected array type")
353    }
354}
355
356/// Encode tuple
357fn encode_tuple(value_str: &str, type_id: u32, metadata: &InkProject) -> Result<Vec<u8>> {
358    let json: JsonValue =
359        serde_json::from_str(value_str).context("Failed to parse tuple as JSON array")?;
360
361    let array = json
362        .as_array()
363        .ok_or_else(|| anyhow::anyhow!("Expected JSON array for tuple"))?;
364
365    let registry = metadata.registry();
366    let ty = registry
367        .resolve(type_id)
368        .ok_or_else(|| anyhow::anyhow!("Type {} not found", type_id))?;
369
370    if let TypeDef::Tuple(tuple_def) = &ty.type_def {
371        if array.len() != tuple_def.fields.len() {
372            anyhow::bail!("Tuple length mismatch");
373        }
374
375        let mut encoded = Vec::new();
376
377        for (element, field_ty) in array.iter().zip(&tuple_def.fields) {
378            let element_str = element.to_string();
379            let element_bytes = encode_value_by_id(&element_str, field_ty.id, metadata)?;
380            encoded.extend_from_slice(&element_bytes);
381        }
382
383        Ok(encoded)
384    } else {
385        anyhow::bail!("Expected tuple type")
386    }
387}
388
389/// Decode query result based on return type
390pub fn decode_result(
391    bytes: &[u8],
392    type_spec: Option<&TypeSpec>,
393    metadata: &InkProject,
394) -> Result<JsonValue> {
395    if let Some(spec) = type_spec {
396        let type_id = spec.ty().id;
397        decode_value_by_id(bytes, type_id, metadata)
398    } else {
399        // No return type (void)
400        Ok(JsonValue::Null)
401    }
402}
403
404/// Decode a value based on its type ID
405fn decode_value_by_id(bytes: &[u8], type_id: u32, metadata: &InkProject) -> Result<JsonValue> {
406    let registry = metadata.registry();
407
408    let ty = registry
409        .resolve(type_id)
410        .ok_or_else(|| anyhow::anyhow!("Type {} not found in registry", type_id))?;
411
412    match &ty.type_def {
413        TypeDef::Primitive(prim) => decode_primitive(bytes, prim),
414        TypeDef::Composite(_) => {
415            // For simplicity, return hex for complex types
416            Ok(JsonValue::String(format!("0x{}", hex::encode(bytes))))
417        }
418        _ => {
419            // For other types, return as hex
420            Ok(JsonValue::String(format!("0x{}", hex::encode(bytes))))
421        }
422    }
423}
424
425/// Decode primitive types
426fn decode_primitive(bytes: &[u8], prim: &TypeDefPrimitive) -> Result<JsonValue> {
427    match prim {
428        TypeDefPrimitive::Bool => {
429            let val = bool::decode(&mut &bytes[..])?;
430            Ok(JsonValue::Bool(val))
431        }
432        TypeDefPrimitive::U8 => {
433            let val = u8::decode(&mut &bytes[..])?;
434            Ok(JsonValue::Number(val.into()))
435        }
436        TypeDefPrimitive::U16 => {
437            let val = u16::decode(&mut &bytes[..])?;
438            Ok(JsonValue::Number(val.into()))
439        }
440        TypeDefPrimitive::U32 => {
441            let val = u32::decode(&mut &bytes[..])?;
442            Ok(JsonValue::Number(val.into()))
443        }
444        TypeDefPrimitive::U64 => {
445            let val = u64::decode(&mut &bytes[..])?;
446            Ok(JsonValue::Number(val.into()))
447        }
448        TypeDefPrimitive::U128 => {
449            let val = u128::decode(&mut &bytes[..])?;
450            Ok(JsonValue::String(val.to_string()))
451        }
452        TypeDefPrimitive::I8 => {
453            let val = i8::decode(&mut &bytes[..])?;
454            Ok(JsonValue::Number(val.into()))
455        }
456        TypeDefPrimitive::I16 => {
457            let val = i16::decode(&mut &bytes[..])?;
458            Ok(JsonValue::Number(val.into()))
459        }
460        TypeDefPrimitive::I32 => {
461            let val = i32::decode(&mut &bytes[..])?;
462            Ok(JsonValue::Number(val.into()))
463        }
464        TypeDefPrimitive::I64 => {
465            let val = i64::decode(&mut &bytes[..])?;
466            Ok(JsonValue::Number(val.into()))
467        }
468        TypeDefPrimitive::I128 => {
469            let val = i128::decode(&mut &bytes[..])?;
470            Ok(JsonValue::String(val.to_string()))
471        }
472        TypeDefPrimitive::Str => {
473            let val = String::decode(&mut &bytes[..])?;
474            Ok(JsonValue::String(val))
475        }
476        _ => Ok(JsonValue::String(format!("0x{}", hex::encode(bytes)))),
477    }
478}