1use 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
10type MessageParamSpec = ink_metadata::MessageParamSpec<PortableForm>;
12type TypeSpec = ink_metadata::TypeSpec<PortableForm>;
13
14pub 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 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
40fn 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 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 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
69fn 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
133fn 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 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 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
175fn encode_account_id(value_str: &str) -> Result<Vec<u8>> {
177 use std::str::FromStr;
178
179 if let Ok(account_id) = AccountId32::from_str(value_str) {
181 return Ok(account_id.0.encode());
182 }
183
184 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
196fn 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 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 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 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
249fn encode_option(value_str: &str, _type_id: u32, _metadata: &InkProject) -> Result<Vec<u8>> {
251 if value_str == "null" || value_str.is_empty() {
252 Ok(vec![0u8])
254 } else {
255 let mut encoded = vec![1u8];
257 encoded.extend_from_slice(&value_str.to_string().encode());
258 Ok(encoded)
259 }
260}
261
262fn 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 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 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
284fn 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 let mut encoded = scale::Compact(array.len() as u32).encode();
303
304 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
317fn 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
356fn 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
389pub 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 Ok(JsonValue::Null)
401 }
402}
403
404fn 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 Ok(JsonValue::String(format!("0x{}", hex::encode(bytes))))
417 }
418 _ => {
419 Ok(JsonValue::String(format!("0x{}", hex::encode(bytes))))
421 }
422 }
423}
424
425fn 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}