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 AccountId32 (special case)
141    if ty.path.segments.last().map(|s| s.as_str()) == Some("AccountId32") {
142        return encode_account_id(value_str);
143    }
144
145    // Try to parse as JSON for complex types
146    let json: JsonValue = serde_json::from_str(value_str)
147        .context("Failed to parse composite value as JSON")?;
148
149    if let TypeDef::Composite(composite) = &ty.type_def {
150        let mut encoded = Vec::new();
151
152        for field in &composite.fields {
153            let field_name = field
154                .name
155                .as_ref()
156                .ok_or_else(|| anyhow::anyhow!("Unnamed field in composite"))?;
157
158            let field_value = json
159                .get(field_name)
160                .ok_or_else(|| anyhow::anyhow!("Missing field: {}", field_name))?
161                .to_string();
162
163            let field_type_id = field.ty.id;
164            let field_bytes = encode_value_by_id(&field_value, field_type_id, metadata)?;
165            encoded.extend_from_slice(&field_bytes);
166        }
167
168        Ok(encoded)
169    } else {
170        anyhow::bail!("Expected composite type")
171    }
172}
173
174/// Encode AccountId32
175fn encode_account_id(value_str: &str) -> Result<Vec<u8>> {
176    use std::str::FromStr;
177
178    // Try parsing as SS58 address
179    if let Ok(account_id) = AccountId32::from_str(value_str) {
180        return Ok(account_id.0.encode());
181    }
182
183    // Try parsing as hex
184    if value_str.starts_with("0x") {
185        let bytes = hex::decode(value_str.trim_start_matches("0x"))
186            .context("Invalid hex address")?;
187        if bytes.len() == 32 {
188            return Ok(bytes);
189        }
190    }
191
192    anyhow::bail!("Invalid AccountId32 format: {}", value_str)
193}
194
195/// Encode variant types (enums, Option, Result)
196fn encode_variant(value_str: &str, type_id: u32, metadata: &InkProject) -> Result<Vec<u8>> {
197    let registry = metadata.registry();
198    let ty = registry
199        .resolve(type_id)
200        .ok_or_else(|| anyhow::anyhow!("Type {} not found", type_id))?;
201
202    // Check for common types: Option, Result
203    let type_name = ty.path.segments.last().map(|s| s.as_str());
204
205    match type_name {
206        Some("Option") => encode_option(value_str, type_id, metadata),
207        Some("Result") => encode_result(value_str, type_id, metadata),
208        _ => {
209            // Generic enum
210            let json: JsonValue =
211                serde_json::from_str(value_str).context("Failed to parse variant as JSON")?;
212
213            if let Some(variant_name) = json.get("variant").and_then(|v| v.as_str()) {
214                if let TypeDef::Variant(variant_def) = &ty.type_def {
215                    let variant = variant_def
216                        .variants
217                        .iter()
218                        .find(|v| v.name == variant_name)
219                        .ok_or_else(|| anyhow::anyhow!("Variant {} not found", variant_name))?;
220
221                    let mut encoded = Vec::new();
222                    encoded.push(variant.index);
223
224                    // Encode variant fields if any
225                    if let Some(fields_json) = json.get("fields") {
226                        for (i, field) in variant.fields.iter().enumerate() {
227                            let field_value = fields_json
228                                .get(i)
229                                .ok_or_else(|| anyhow::anyhow!("Missing variant field {}", i))?
230                                .to_string();
231
232                            let field_type_id = field.ty.id;
233                            let field_bytes = encode_value_by_id(&field_value, field_type_id, metadata)?;
234                            encoded.extend_from_slice(&field_bytes);
235                        }
236                    }
237
238                    return Ok(encoded);
239                }
240            }
241
242            anyhow::bail!("Invalid variant encoding")
243        }
244    }
245}
246
247/// Encode Option type
248fn encode_option(value_str: &str, _type_id: u32, _metadata: &InkProject) -> Result<Vec<u8>> {
249    if value_str == "null" || value_str.is_empty() {
250        // None variant (index 0)
251        Ok(vec![0u8])
252    } else {
253        // Some variant (index 1) + encoded value
254        let mut encoded = vec![1u8];
255        encoded.extend_from_slice(&value_str.to_string().encode());
256        Ok(encoded)
257    }
258}
259
260/// Encode Result type
261fn encode_result(value_str: &str, _type_id: u32, _metadata: &InkProject) -> Result<Vec<u8>> {
262    let json: JsonValue =
263        serde_json::from_str(value_str).context("Failed to parse Result as JSON")?;
264
265    if json.get("Ok").is_some() {
266        // Ok variant (index 0)
267        let mut encoded = vec![0u8];
268        let ok_value = json.get("Ok").unwrap().to_string();
269        encoded.extend_from_slice(&ok_value.encode());
270        Ok(encoded)
271    } else if json.get("Err").is_some() {
272        // Err variant (index 1)
273        let mut encoded = vec![1u8];
274        let err_value = json.get("Err").unwrap().to_string();
275        encoded.extend_from_slice(&err_value.encode());
276        Ok(encoded)
277    } else {
278        anyhow::bail!("Invalid Result format")
279    }
280}
281
282/// Encode sequence (Vec)
283fn encode_sequence(value_str: &str, type_id: u32, metadata: &InkProject) -> Result<Vec<u8>> {
284    let json: JsonValue =
285        serde_json::from_str(value_str).context("Failed to parse sequence as JSON array")?;
286
287    let array = json
288        .as_array()
289        .ok_or_else(|| anyhow::anyhow!("Expected JSON array"))?;
290
291    let registry = metadata.registry();
292    let ty = registry
293        .resolve(type_id)
294        .ok_or_else(|| anyhow::anyhow!("Type {} not found", type_id))?;
295
296    if let TypeDef::Sequence(seq) = &ty.type_def {
297        let element_type_id = seq.type_param.id;
298
299        // Encode length as compact
300        let mut encoded = scale::Compact(array.len() as u32).encode();
301
302        // Encode each element
303        for element in array {
304            let element_str = element.to_string();
305            let element_bytes = encode_value_by_id(&element_str, element_type_id, metadata)?;
306            encoded.extend_from_slice(&element_bytes);
307        }
308
309        Ok(encoded)
310    } else {
311        anyhow::bail!("Expected sequence type")
312    }
313}
314
315/// Encode array
316fn encode_array(value_str: &str, type_id: u32, metadata: &InkProject) -> Result<Vec<u8>> {
317    let json: JsonValue =
318        serde_json::from_str(value_str).context("Failed to parse array as JSON")?;
319
320    let array = json
321        .as_array()
322        .ok_or_else(|| anyhow::anyhow!("Expected JSON array"))?;
323
324    let registry = metadata.registry();
325    let ty = registry
326        .resolve(type_id)
327        .ok_or_else(|| anyhow::anyhow!("Type {} not found", type_id))?;
328
329    if let TypeDef::Array(arr_def) = &ty.type_def {
330        let element_type_id = arr_def.type_param.id;
331
332        if array.len() != arr_def.len as usize {
333            anyhow::bail!(
334                "Array length mismatch: expected {}, got {}",
335                arr_def.len,
336                array.len()
337            );
338        }
339
340        let mut encoded = Vec::new();
341
342        for element in array {
343            let element_str = element.to_string();
344            let element_bytes = encode_value_by_id(&element_str, element_type_id, metadata)?;
345            encoded.extend_from_slice(&element_bytes);
346        }
347
348        Ok(encoded)
349    } else {
350        anyhow::bail!("Expected array type")
351    }
352}
353
354/// Encode tuple
355fn encode_tuple(value_str: &str, type_id: u32, metadata: &InkProject) -> Result<Vec<u8>> {
356    let json: JsonValue =
357        serde_json::from_str(value_str).context("Failed to parse tuple as JSON array")?;
358
359    let array = json
360        .as_array()
361        .ok_or_else(|| anyhow::anyhow!("Expected JSON array for tuple"))?;
362
363    let registry = metadata.registry();
364    let ty = registry
365        .resolve(type_id)
366        .ok_or_else(|| anyhow::anyhow!("Type {} not found", type_id))?;
367
368    if let TypeDef::Tuple(tuple_def) = &ty.type_def {
369        if array.len() != tuple_def.fields.len() {
370            anyhow::bail!("Tuple length mismatch");
371        }
372
373        let mut encoded = Vec::new();
374
375        for (element, field_ty) in array.iter().zip(&tuple_def.fields) {
376            let element_str = element.to_string();
377            let element_bytes = encode_value_by_id(&element_str, field_ty.id, metadata)?;
378            encoded.extend_from_slice(&element_bytes);
379        }
380
381        Ok(encoded)
382    } else {
383        anyhow::bail!("Expected tuple type")
384    }
385}
386
387/// Decode query result based on return type
388pub fn decode_result(
389    bytes: &[u8],
390    type_spec: Option<&TypeSpec>,
391    metadata: &InkProject,
392) -> Result<JsonValue> {
393    if let Some(spec) = type_spec {
394        let type_id = spec.ty().id;
395        decode_value_by_id(bytes, type_id, metadata)
396    } else {
397        // No return type (void)
398        Ok(JsonValue::Null)
399    }
400}
401
402/// Decode a value based on its type ID
403fn decode_value_by_id(bytes: &[u8], type_id: u32, metadata: &InkProject) -> Result<JsonValue> {
404    let registry = metadata.registry();
405
406    let ty = registry
407        .resolve(type_id)
408        .ok_or_else(|| anyhow::anyhow!("Type {} not found in registry", type_id))?;
409
410    match &ty.type_def {
411        TypeDef::Primitive(prim) => decode_primitive(bytes, prim),
412        TypeDef::Composite(_) => {
413            // For simplicity, return hex for complex types
414            Ok(JsonValue::String(format!("0x{}", hex::encode(bytes))))
415        }
416        _ => {
417            // For other types, return as hex
418            Ok(JsonValue::String(format!("0x{}", hex::encode(bytes))))
419        }
420    }
421}
422
423/// Decode primitive types
424fn decode_primitive(bytes: &[u8], prim: &TypeDefPrimitive) -> Result<JsonValue> {
425    match prim {
426        TypeDefPrimitive::Bool => {
427            let val = bool::decode(&mut &bytes[..])?;
428            Ok(JsonValue::Bool(val))
429        }
430        TypeDefPrimitive::U8 => {
431            let val = u8::decode(&mut &bytes[..])?;
432            Ok(JsonValue::Number(val.into()))
433        }
434        TypeDefPrimitive::U16 => {
435            let val = u16::decode(&mut &bytes[..])?;
436            Ok(JsonValue::Number(val.into()))
437        }
438        TypeDefPrimitive::U32 => {
439            let val = u32::decode(&mut &bytes[..])?;
440            Ok(JsonValue::Number(val.into()))
441        }
442        TypeDefPrimitive::U64 => {
443            let val = u64::decode(&mut &bytes[..])?;
444            Ok(JsonValue::Number(val.into()))
445        }
446        TypeDefPrimitive::U128 => {
447            let val = u128::decode(&mut &bytes[..])?;
448            Ok(JsonValue::String(val.to_string()))
449        }
450        TypeDefPrimitive::I8 => {
451            let val = i8::decode(&mut &bytes[..])?;
452            Ok(JsonValue::Number(val.into()))
453        }
454        TypeDefPrimitive::I16 => {
455            let val = i16::decode(&mut &bytes[..])?;
456            Ok(JsonValue::Number(val.into()))
457        }
458        TypeDefPrimitive::I32 => {
459            let val = i32::decode(&mut &bytes[..])?;
460            Ok(JsonValue::Number(val.into()))
461        }
462        TypeDefPrimitive::I64 => {
463            let val = i64::decode(&mut &bytes[..])?;
464            Ok(JsonValue::Number(val.into()))
465        }
466        TypeDefPrimitive::I128 => {
467            let val = i128::decode(&mut &bytes[..])?;
468            Ok(JsonValue::String(val.to_string()))
469        }
470        TypeDefPrimitive::Str => {
471            let val = String::decode(&mut &bytes[..])?;
472            Ok(JsonValue::String(val))
473        }
474        _ => Ok(JsonValue::String(format!("0x{}", hex::encode(bytes)))),
475    }
476}