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 if ty.path.segments.last().map(|s| s.as_str()) == Some("AccountId32") {
142 return encode_account_id(value_str);
143 }
144
145 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
174fn encode_account_id(value_str: &str) -> Result<Vec<u8>> {
176 use std::str::FromStr;
177
178 if let Ok(account_id) = AccountId32::from_str(value_str) {
180 return Ok(account_id.0.encode());
181 }
182
183 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
195fn 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 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 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 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
247fn encode_option(value_str: &str, _type_id: u32, _metadata: &InkProject) -> Result<Vec<u8>> {
249 if value_str == "null" || value_str.is_empty() {
250 Ok(vec![0u8])
252 } else {
253 let mut encoded = vec![1u8];
255 encoded.extend_from_slice(&value_str.to_string().encode());
256 Ok(encoded)
257 }
258}
259
260fn 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 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 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
282fn 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 let mut encoded = scale::Compact(array.len() as u32).encode();
301
302 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
315fn 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
354fn 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
387pub 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 Ok(JsonValue::Null)
399 }
400}
401
402fn 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 Ok(JsonValue::String(format!("0x{}", hex::encode(bytes))))
415 }
416 _ => {
417 Ok(JsonValue::String(format!("0x{}", hex::encode(bytes))))
419 }
420 }
421}
422
423fn 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}