1mod account_id;
102mod decode;
103mod encode;
104pub mod env_types;
105mod scon;
106mod transcoder;
107mod util;
108
109pub use self::{
110 account_id::AccountId32,
111 scon::{
112 Hex,
113 Map,
114 Tuple,
115 Value,
116 },
117 transcoder::{
118 Transcoder,
119 TranscoderBuilder,
120 },
121};
122
123use anyhow::{
124 Context,
125 Result,
126};
127pub use ink_metadata;
128use ink_metadata::{
129 ConstructorSpec,
130 InkProject,
131 MessageSpec,
132};
133use itertools::Itertools;
134use regex::Regex;
135use scale::{
136 Compact,
137 Decode,
138 Input,
139};
140use scale_info::{
141 Field,
142 PortableRegistry,
143 TypeDef,
144 TypeDefPrimitive,
145 form::{
146 Form,
147 PortableForm,
148 },
149};
150use std::{
151 cmp::Ordering,
152 fmt::Debug,
153 path::Path,
154};
155
156pub struct ContractMessageTranscoder {
159 metadata: InkProject,
160 transcoder: Transcoder,
161}
162
163fn did_you_mean<T, I>(v: &str, possible_values: I) -> Vec<String>
168where
169 T: AsRef<str>,
170 I: IntoIterator<Item = T>,
171{
172 let mut candidates: Vec<(f64, String)> = possible_values
173 .into_iter()
174 .map(|pv| (strsim::jaro(v, pv.as_ref()), pv.as_ref().to_owned()))
175 .filter(|(confidence, _)| *confidence > 0.7)
176 .collect();
177 candidates.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal));
178 candidates.into_iter().map(|(_, pv)| pv).collect()
179}
180
181fn parse_with_type_hint(
199 arg: &str,
200 type_id: u32,
201 registry: &PortableRegistry,
202) -> Result<Value> {
203 let ty = registry
205 .resolve(type_id)
206 .ok_or_else(|| anyhow::anyhow!("Type {type_id} not found in registry"))?;
207 if matches!(&ty.type_def, TypeDef::Primitive(TypeDefPrimitive::Str)) {
209 if arg.starts_with('"') && arg.ends_with('"') {
211 return scon::parse_value(arg);
212 }
213 return Ok(Value::String(arg.to_string()));
216 }
217 scon::parse_value(arg)
219}
220
221impl ContractMessageTranscoder {
222 pub fn new(metadata: InkProject) -> Self {
223 let transcoder = TranscoderBuilder::new(metadata.registry())
224 .with_default_custom_type_transcoders()
225 .done();
226 Self {
227 metadata,
228 transcoder,
229 }
230 }
231
232 pub fn load<P>(metadata_path: P) -> Result<Self>
235 where
236 P: AsRef<Path>,
237 {
238 let path = metadata_path.as_ref();
239 let metadata: contract_metadata::ContractMetadata =
240 contract_metadata::ContractMetadata::load(&metadata_path)?;
241 let ink_metadata = serde_json::from_value(serde_json::Value::Object(
242 metadata.abi,
243 ))
244 .context(format!(
245 "Failed to deserialize ink project metadata from file {}",
246 path.display()
247 ))?;
248
249 Ok(Self::new(ink_metadata))
250 }
251
252 pub fn encode<I, S>(&self, name: &str, args: I) -> Result<Vec<u8>>
253 where
254 I: IntoIterator<Item = S>,
255 S: AsRef<str> + Debug,
256 {
257 let (selector, spec_args) = match (
258 self.find_constructor_spec(name),
259 self.find_message_spec(name),
260 ) {
261 (Some(c), None) => (c.selector(), c.args()),
262 (None, Some(m)) => (m.selector(), m.args()),
263 (Some(_), Some(_)) => {
264 return Err(anyhow::anyhow!(
265 "Invalid metadata: both a constructor and message found with name '{name}'"
266 ));
267 }
268 (None, None) => {
269 let constructors = self.constructors().map(|c| c.label());
270 let messages = self.messages().map(|c| c.label());
271 let possible_values: Vec<_> = constructors.chain(messages).collect();
272 let help_txt = did_you_mean(name, possible_values.clone())
273 .first()
274 .map(|suggestion| format!("Did you mean '{suggestion}'?"))
275 .unwrap_or_else(|| {
276 format!("Should be one of: {}", possible_values.iter().join(", "))
277 });
278
279 return Err(anyhow::anyhow!(
280 "No constructor or message with the name '{name}' found.\n{help_txt}",
281 ));
282 }
283 };
284
285 let args: Vec<_> = args.into_iter().collect();
286 if spec_args.len() != args.len() {
287 anyhow::bail!(
288 "Invalid number of input arguments: expected {}, {} provided",
289 spec_args.len(),
290 args.len()
291 )
292 }
293
294 let mut encoded = selector.to_bytes().to_vec();
295 for (spec, arg) in spec_args.iter().zip(args) {
296 assert_not_shortened_hex(arg.as_ref());
297
298 let value = parse_with_type_hint(
301 arg.as_ref(),
302 spec.ty().ty().id,
303 self.metadata.registry(),
304 )?;
305
306 self.transcoder.encode(
307 self.metadata.registry(),
308 spec.ty().ty().id,
309 &value,
310 &mut encoded,
311 )?;
312 }
313 Ok(encoded)
314 }
315
316 pub fn decode(&self, type_id: u32, input: &mut &[u8]) -> Result<Value> {
317 self.transcoder
318 .decode(self.metadata.registry(), type_id, input)
319 }
320
321 pub fn metadata(&self) -> &InkProject {
322 &self.metadata
323 }
324
325 fn constructors(&self) -> impl Iterator<Item = &ConstructorSpec<PortableForm>> {
326 self.metadata.spec().constructors().iter()
327 }
328
329 fn messages(&self) -> impl Iterator<Item = &MessageSpec<PortableForm>> {
330 self.metadata.spec().messages().iter()
331 }
332
333 fn find_message_spec(&self, name: &str) -> Option<&MessageSpec<PortableForm>> {
334 self.messages().find(|msg| msg.label() == &name.to_string())
335 }
336
337 fn find_constructor_spec(
338 &self,
339 name: &str,
340 ) -> Option<&ConstructorSpec<PortableForm>> {
341 self.constructors()
342 .find(|msg| msg.label() == &name.to_string())
343 }
344
345 pub fn decode_contract_event<Hash>(
346 &self,
347 event_sig_topic: &Hash,
348 data: &mut &[u8],
349 ) -> Result<Value>
350 where
351 Hash: AsRef<[u8]>,
352 {
353 let _len = <Compact<u32>>::decode(data)?;
357 let event_spec = self
358 .metadata
359 .spec()
360 .events()
361 .iter()
362 .find(|event| {
363 if let Some(sig_topic) = event.signature_topic() {
364 sig_topic.as_bytes() == event_sig_topic.as_ref()
365 } else {
366 false
367 }
368 })
369 .ok_or_else(|| {
370 anyhow::anyhow!(
371 "Event with signature topic {} not found in contract metadata",
372 hex::encode(event_sig_topic)
373 )
374 })?;
375 tracing::debug!("Decoding contract event '{}'", event_spec.label());
376
377 let mut args = Vec::new();
378 for arg in event_spec.args() {
379 let name = arg.label().to_string();
380 let value = self.decode(arg.ty().ty().id, data)?;
381 args.push((Value::String(name), value));
382 }
383
384 Self::validate_length(data, event_spec.label(), &args)?;
385
386 let name = event_spec.label().to_string();
387 let map = Map::new(Some(&name), args.into_iter().collect());
388
389 Ok(Value::Map(map))
390 }
391
392 pub fn decode_contract_message(&self, data: &mut &[u8]) -> Result<Value> {
393 let mut msg_selector = [0u8; 4];
394 data.read(&mut msg_selector)?;
395 let msg_spec = self
396 .messages()
397 .find(|x| msg_selector == x.selector().to_bytes())
398 .ok_or_else(|| {
399 anyhow::anyhow!(
400 "Message with selector {} not found in contract metadata",
401 hex::encode_upper(msg_selector)
402 )
403 })?;
404 tracing::debug!("Decoding contract message '{}'", msg_spec.label());
405
406 let mut args = Vec::new();
407 for arg in msg_spec.args() {
408 let name = arg.label().to_string();
409 let value = self.decode(arg.ty().ty().id, data)?;
410 args.push((Value::String(name), value));
411 }
412
413 Self::validate_length(data, msg_spec.label(), &args)?;
414
415 let name = msg_spec.label().to_string();
416 let map = Map::new(Some(&name), args.into_iter().collect());
417
418 Ok(Value::Map(map))
419 }
420
421 pub fn decode_contract_constructor(&self, data: &mut &[u8]) -> Result<Value> {
422 let mut msg_selector = [0u8; 4];
423 data.read(&mut msg_selector)?;
424 let msg_spec = self
425 .constructors()
426 .find(|x| msg_selector == x.selector().to_bytes())
427 .ok_or_else(|| {
428 anyhow::anyhow!(
429 "Constructor with selector {} not found in contract metadata",
430 hex::encode_upper(msg_selector)
431 )
432 })?;
433 tracing::debug!("Decoding contract constructor '{}'", msg_spec.label());
434
435 let mut args = Vec::new();
436 for arg in msg_spec.args() {
437 let name = arg.label().to_string();
438 let value = self.decode(arg.ty().ty().id, data)?;
439 args.push((Value::String(name), value));
440 }
441
442 Self::validate_length(data, msg_spec.label(), &args)?;
443
444 let name = msg_spec.label().to_string();
445 let map = Map::new(Some(&name), args.into_iter().collect());
446
447 Ok(Value::Map(map))
448 }
449
450 pub fn decode_constructor_return(
451 &self,
452 name: &str,
453 data: &mut &[u8],
454 ) -> Result<Value> {
455 let ctor_spec = self.find_constructor_spec(name).ok_or_else(|| {
456 anyhow::anyhow!("Failed to find constructor spec with name '{name}'")
457 })?;
458 let return_ty = ctor_spec.return_type().ret_type();
459 self.decode(return_ty.ty().id, data)
460 }
461
462 pub fn decode_message_return(&self, name: &str, data: &mut &[u8]) -> Result<Value> {
463 let msg_spec = self.find_message_spec(name).ok_or_else(|| {
464 anyhow::anyhow!("Failed to find message spec with name '{name}'")
465 })?;
466 let return_ty = msg_spec.return_type().ret_type();
467 self.decode(return_ty.ty().id, data)
468 }
469
470 fn validate_length(data: &[u8], label: &str, args: &[(Value, Value)]) -> Result<()> {
472 if !data.is_empty() {
473 let arg_list_string: String =
474 args.iter().fold(format!("`{label}`"), |init, arg| {
475 format!("{}, `{}`", init, arg.0)
476 });
477 let encoded_bytes = hex::encode_upper(data);
478 return Err(anyhow::anyhow!(
479 "input length was longer than expected by {} byte(s).\nManaged to decode {} but `{}` bytes were left unread",
480 data.len(),
481 arg_list_string,
482 encoded_bytes
483 ));
484 }
485 Ok(())
486 }
487}
488
489fn assert_not_shortened_hex(arg: &str) {
491 let re = Regex::new(r"^0x[a-fA-F0-9]+…[a-fA-F0-9]+$").unwrap();
492 if re.is_match(arg) {
493 panic!(
494 "Error: You are attempting to transcode a shortened hex value: `{arg:?}`.\n\
495 This would result in a different return value than the un-shortened hex value.\n\
496 You likely called `to_string()` on e.g. `H160` and got a shortened output."
497 );
498 }
499}
500
501impl TryFrom<contract_metadata::ContractMetadata> for ContractMessageTranscoder {
502 type Error = anyhow::Error;
503
504 fn try_from(
505 metadata: contract_metadata::ContractMetadata,
506 ) -> Result<Self, Self::Error> {
507 Ok(Self::new(serde_json::from_value(
508 serde_json::Value::Object(metadata.abi),
509 )?))
510 }
511}
512
513#[derive(Debug)]
514pub enum CompositeTypeFields {
515 Named(Vec<CompositeTypeNamedField>),
516 Unnamed(Vec<Field<PortableForm>>),
517 NoFields,
518}
519
520#[derive(Debug)]
521pub struct CompositeTypeNamedField {
522 name: <PortableForm as Form>::String,
523 field: Field<PortableForm>,
524}
525
526impl CompositeTypeNamedField {
527 pub fn name(&self) -> &str {
528 &self.name
529 }
530
531 pub fn field(&self) -> &Field<PortableForm> {
532 &self.field
533 }
534}
535
536impl CompositeTypeFields {
537 pub fn from_fields(fields: &[Field<PortableForm>]) -> Result<Self> {
538 if fields.iter().next().is_none() {
539 Ok(Self::NoFields)
540 } else if fields.iter().all(|f| f.name.is_some()) {
541 let fields = fields
542 .iter()
543 .map(|field| {
544 CompositeTypeNamedField {
545 name: field
546 .name
547 .as_ref()
548 .expect("All fields have a name; qed")
549 .to_owned(),
550 field: field.clone(),
551 }
552 })
553 .collect();
554 Ok(Self::Named(fields))
555 } else if fields.iter().all(|f| f.name.is_none()) {
556 Ok(Self::Unnamed(fields.to_vec()))
557 } else {
558 Err(anyhow::anyhow!(
559 "Struct fields should either be all named or all unnamed"
560 ))
561 }
562 }
563}
564
565#[cfg(test)]
566#[allow(unused_imports, unexpected_cfgs)]
568mod tests {
569 use super::*;
570 use crate::scon::Hex;
571 use ink_env::{
572 DefaultEnvironment,
573 Environment,
574 };
575 use primitive_types::H256;
576 use scale::Encode;
577 use scon::Value;
578 use std::str::FromStr;
579
580 #[allow(clippy::extra_unused_lifetimes, non_local_definitions)]
581 #[ink::contract]
582 pub mod transcode {
583 #[ink(storage)]
584 pub struct Transcode {
585 value: bool,
586 }
587
588 #[ink(event)]
589 pub struct Event1 {
590 #[ink(topic)]
591 name: Hash,
592 #[ink(topic)]
593 from: AccountId,
594 }
595
596 impl Transcode {
597 #[ink(constructor)]
598 pub fn new(init_value: bool) -> Self {
599 Self { value: init_value }
600 }
601
602 #[ink(constructor)]
603 pub fn default() -> Self {
604 Self::new(Default::default())
605 }
606
607 #[ink(message)]
608 pub fn flip(&mut self) {
609 self.value = !self.value;
610 }
611
612 #[ink(message)]
613 pub fn get(&self) -> bool {
614 self.value
615 }
616
617 #[ink(message)]
618 pub fn get_complex(
619 &self,
620 ) -> (u32, ink::H160, ink::H256, ink::U256, AccountId) {
621 (
622 32u32,
623 self.env().address(),
624 self.env().own_code_hash(),
625 ink::U256::one(),
627 AccountId::from([0x17; 32]),
628 )
629 }
630 #[ink(message)]
640 pub fn set_account_id(&self, account_id: AccountId) {
641 let _ = account_id;
642 }
643
644 #[ink(message)]
645 pub fn set_account_ids_vec(&self, account_ids: Vec<AccountId>) {
646 let _ = account_ids;
647 }
648
649 #[ink(message)]
650 pub fn primitive_vec_args(&self, args: Vec<u32>) {
651 let _ = args;
652 }
653
654 #[ink(message)]
655 pub fn uint_args(
656 &self,
657 _u8: u8,
658 _u16: u16,
659 _u32: u32,
660 _u64: u64,
661 _u128: u128,
662 ) {
663 }
664
665 #[ink(message)]
666 pub fn uint_array_args(&self, arr: [u8; 4]) {
667 let _ = arr;
668 }
669
670 #[ink(message)]
671 pub fn h160(&self, addr: ink::H160) {
672 let _ = addr;
673 }
674
675 #[ink(message)]
676 pub fn set_name(&self, _name: String) {}
677 }
678 }
679
680 fn generate_metadata() -> InkProject {
681 unsafe extern "Rust" {
682 fn __ink_generate_metadata() -> InkProject;
683 }
684
685 unsafe { __ink_generate_metadata() }
686 }
687
688 #[test]
689 fn encode_single_primitive_arg() -> Result<()> {
690 let metadata = generate_metadata();
691 let transcoder = ContractMessageTranscoder::new(metadata);
692
693 let encoded = transcoder.encode("new", ["true"])?;
694 let encoded_args = &encoded[4..];
696
697 assert_eq!(true.encode(), encoded_args);
698 Ok(())
699 }
700
701 #[test]
702 fn encode_misspelled_arg() {
703 let metadata = generate_metadata();
704 let transcoder = ContractMessageTranscoder::new(metadata);
705 assert_eq!(
706 transcoder.encode("fip", ["true"]).unwrap_err().to_string(),
707 "No constructor or message with the name 'fip' found.\nDid you mean 'flip'?"
708 );
709 }
710
711 #[test]
712 fn encode_mismatching_args_length() {
713 let metadata = generate_metadata();
714 let transcoder = ContractMessageTranscoder::new(metadata);
715
716 let result: Result<Vec<u8>> = transcoder.encode("new", Vec::<&str>::new());
717 assert!(result.is_err(), "Should return an error");
718 assert_eq!(
719 result.unwrap_err().to_string(),
720 "Invalid number of input arguments: expected 1, 0 provided"
721 );
722
723 let result: Result<Vec<u8>> = transcoder.encode("new", ["true", "false"]);
724 assert!(result.is_err(), "Should return an error");
725 assert_eq!(
726 result.unwrap_err().to_string(),
727 "Invalid number of input arguments: expected 1, 2 provided"
728 );
729 }
730
731 #[test]
732 fn encode_account_id_custom_ss58_encoding() -> Result<()> {
733 let metadata = generate_metadata();
734 let transcoder = ContractMessageTranscoder::new(metadata);
735
736 let encoded = transcoder.encode(
737 "set_account_id",
738 ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"],
739 )?;
740
741 let encoded_args = &encoded[4..];
743
744 let expected =
745 AccountId32::from_str("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY")
746 .unwrap();
747 assert_eq!(expected.encode(), encoded_args);
748 Ok(())
749 }
750
751 #[test]
752 fn encode_account_ids_vec_args() -> Result<()> {
753 let metadata = generate_metadata();
754 let transcoder = ContractMessageTranscoder::new(metadata);
755
756 let encoded = transcoder.encode(
757 "set_account_ids_vec",
758 ["[5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY, 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty]"],
759 )?;
760
761 let encoded_args = &encoded[4..];
763
764 let expected = vec![
765 AccountId32::from_str("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY")
766 .unwrap(),
767 AccountId32::from_str("5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty")
768 .unwrap(),
769 ];
770 assert_eq!(expected.encode(), encoded_args);
771 Ok(())
772 }
773
774 #[test]
775 fn encode_primitive_vec_args() -> Result<()> {
776 let metadata = generate_metadata();
777 let transcoder = ContractMessageTranscoder::new(metadata);
778
779 let encoded = transcoder.encode("primitive_vec_args", ["[1, 2]"])?;
780
781 let encoded_args = &encoded[4..];
783
784 let expected = vec![1, 2];
785 assert_eq!(expected.encode(), encoded_args);
786 Ok(())
787 }
788
789 #[test]
790 fn encode_uint_hex_literals() -> Result<()> {
791 let metadata = generate_metadata();
792 let transcoder = ContractMessageTranscoder::new(metadata);
793
794 let encoded = transcoder.encode(
795 "uint_args",
796 [
797 "0x00",
798 "0xDEAD",
799 "0xDEADBEEF",
800 "0xDEADBEEF12345678",
801 "0xDEADBEEF0123456789ABCDEF01234567",
802 ],
803 )?;
804
805 let encoded_args = &encoded[4..];
807
808 let expected = (
809 0x00u8,
810 0xDEADu16,
811 0xDEADBEEFu32,
812 0xDEADBEEF12345678u64,
813 0xDEADBEEF0123456789ABCDEF01234567u128,
814 );
815 assert_eq!(expected.encode(), encoded_args);
816 Ok(())
817 }
818
819 #[test]
820 fn encode_uint_arr_hex_literals() -> Result<()> {
821 let metadata = generate_metadata();
822 let transcoder = ContractMessageTranscoder::new(metadata);
823
824 let encoded =
825 transcoder.encode("uint_array_args", ["[0xDE, 0xAD, 0xBE, 0xEF]"])?;
826
827 let encoded_args = &encoded[4..];
829
830 let expected: [u8; 4] = [0xDE, 0xAD, 0xBE, 0xEF];
831 assert_eq!(expected.encode(), encoded_args);
832 Ok(())
833 }
834
835 #[test]
836 #[should_panic(
837 expected = "Error: You are attempting to transcode a shortened hex value: `\"0xbc3f…f58a\"`"
838 )]
839 fn encode_must_panic_on_shortened_hex() {
840 let metadata = generate_metadata();
841 let transcoder = ContractMessageTranscoder::new(metadata);
842
843 let _encoded = transcoder.encode("h160", ["0xbc3f…f58a"]);
844 }
845
846 #[test]
847 fn decode_complex_return() {
848 let metadata = generate_metadata();
849 let transcoder = ContractMessageTranscoder::new(metadata);
850
851 let addr: ink::H160 = ink::H160::from([0x42; 20]);
852 let account_id: AccountId32 = AccountId32::from([0x13; 32]);
853 let _hash: [u8; 32] = [0xAB; 32];
854 let h256: ink::H256 = ink::H256::from([0x17; 32]);
855 let value: ink::U256 = ink::U256::one();
857
858 let encoded = Result::<
859 (u32, ink::H160, ink::H256, ink::U256, AccountId32),
860 ink::primitives::LangError,
861 >::Ok((32, addr, h256, value, account_id))
862 .encode();
863
864 let decoded = transcoder
865 .decode_message_return("get_complex", &mut &encoded[..])
866 .unwrap_or_else(|e| panic!("Error decoding return value {e}"));
867
868 let expected = Value::Tuple(Tuple::new(
869 "Ok".into(),
870 [
871 Value::Tuple(Tuple::new(
872 None,
873 [
874 Value::UInt(32),
875 Value::Hex(Hex::from_str("0x4242424242424242424242424242424242424242").unwrap()),
876 Value::Hex(Hex::from_str("0x1717171717171717171717171717171717171717171717171717171717171717").unwrap()),
877 Value::Literal("1".to_string()),
878 Value::Literal("5CViS5pKamF1VbJ9tmQKPNDpLpJaBCfpPw2m49UzQ8zgiDGT".to_string()),
879 ]
880 .into_iter().collect()
881 ))
882 ]
883 .into_iter().collect(),
884 ));
885 assert_eq!(expected, decoded);
886 }
887
888 #[test]
889 fn decode_primitive_return() {
890 let metadata = generate_metadata();
891 let transcoder = ContractMessageTranscoder::new(metadata);
892
893 let encoded = Result::<bool, ink::primitives::LangError>::Ok(true).encode();
894 let decoded = transcoder
895 .decode_message_return("get", &mut &encoded[..])
896 .unwrap_or_else(|e| panic!("Error decoding return value {e}"));
897
898 let expected = Value::Tuple(Tuple::new(
899 "Ok".into(),
900 [Value::Bool(true)].into_iter().collect(),
901 ));
902 assert_eq!(expected, decoded);
903 }
904
905 #[test]
906 fn decode_lang_error() {
907 use ink::primitives::LangError;
908
909 let metadata = generate_metadata();
910 let transcoder = ContractMessageTranscoder::new(metadata);
911
912 let encoded =
913 Result::<bool, LangError>::Err(LangError::CouldNotReadInput).encode();
914 let decoded = transcoder
915 .decode_message_return("get", &mut &encoded[..])
916 .unwrap_or_else(|e| panic!("Error decoding return value {e}"));
917
918 let expected = Value::Tuple(Tuple::new(
919 "Err".into(),
920 [Value::Tuple(Tuple::new(
921 Some("CouldNotReadInput"),
922 Vec::new(),
923 ))]
924 .to_vec(),
925 ));
926 assert_eq!(expected, decoded);
927 }
928
929 #[test]
930 fn decode_contract_event() -> Result<()> {
931 let metadata = generate_metadata();
932 let transcoder = ContractMessageTranscoder::new(metadata);
933
934 let signature_topic: <DefaultEnvironment as Environment>::Hash =
935 <transcode::Event1 as ink::env::Event>::SIGNATURE_TOPIC
936 .unwrap()
937 .into();
938 let encoded = ([0u32; 8], [1u32; 8]).encode();
940 let encoded_bytes = encoded.encode();
942 let _ = transcoder
943 .decode_contract_event(&signature_topic, &mut &encoded_bytes[..])?;
944
945 Ok(())
948 }
949
950 #[test]
951 fn decode_hash_as_hex_encoded_string() -> Result<()> {
952 let metadata = generate_metadata();
953 let transcoder = ContractMessageTranscoder::new(metadata);
954
955 let hash = [
956 52u8, 40, 235, 225, 70, 245, 184, 36, 21, 218, 130, 114, 75, 207, 117, 240,
957 83, 118, 135, 56, 220, 172, 95, 131, 171, 125, 130, 167, 10, 15, 242, 222,
958 ];
959 let signature_topic: <DefaultEnvironment as Environment>::Hash =
960 <transcode::Event1 as ink::env::Event>::SIGNATURE_TOPIC
961 .unwrap()
962 .into();
963 let encoded = (hash, [0u32; 8]).encode();
965 let encoded_bytes = encoded.encode();
967 let decoded = transcoder
968 .decode_contract_event(&signature_topic, &mut &encoded_bytes[..])?;
969
970 if let Value::Map(ref map) = decoded {
971 let name_field = &map[&Value::String("name".into())];
972 if let Value::Hex(hex) = name_field {
973 assert_eq!(
974 &Hex::from_str(
975 "0x3428ebe146f5b82415da82724bcf75f053768738dcac5f83ab7d82a70a0ff2de"
976 )?,
977 hex
978 );
979 Ok(())
980 } else {
981 Err(anyhow::anyhow!(
982 "Expected a name field hash encoded as Hex value, was {name_field:?}"
983 ))
984 }
985 } else {
986 Err(anyhow::anyhow!(
987 "Expected a Value::Map for the decoded event"
988 ))
989 }
990 }
991
992 #[test]
993 fn decode_contract_message() -> Result<()> {
994 let metadata = generate_metadata();
995 let transcoder = ContractMessageTranscoder::new(metadata);
996
997 let encoded_bytes = hex::decode("633aa551").unwrap();
998 let _ = transcoder.decode_contract_message(&mut &encoded_bytes[..])?;
999
1000 Ok(())
1001 }
1002
1003 #[test]
1004 #[should_panic(
1005 expected = "input length was longer than expected by 1 byte(s).\nManaged to decode `flip` but `00` bytes were left unread"
1006 )]
1007 fn fail_decode_input_with_extra_bytes() {
1008 let metadata = generate_metadata();
1009 let transcoder = ContractMessageTranscoder::new(metadata);
1010
1011 let encoded_bytes = hex::decode("633aa55100").unwrap();
1012 let _ = transcoder
1013 .decode_contract_message(&mut &encoded_bytes[..])
1014 .unwrap();
1015 }
1016
1017 #[test]
1018 #[should_panic(
1019 expected = "input length was longer than expected by 2 byte(s).\nManaged to decode `Event1`, `name`, `from` but `0C10` bytes were left unread"
1020 )]
1021 fn fail_decode_contract_event_with_extra_bytes() {
1022 let metadata = generate_metadata();
1023 let transcoder = ContractMessageTranscoder::new(metadata);
1024
1025 let signature_topic: H256 =
1026 <transcode::Event1 as ink::env::Event>::SIGNATURE_TOPIC
1027 .unwrap()
1028 .into();
1029 let encoded = ([0u32; 8], [1u32; 8], [12u8, 16u8]).encode();
1031 let encoded_bytes = encoded.encode();
1033 let _ = transcoder
1034 .decode_contract_event(&signature_topic, &mut &encoded_bytes[..])
1035 .unwrap();
1036 }
1037
1038 #[test]
1039 fn encode_string_quoted_traditional() -> Result<()> {
1040 let metadata = generate_metadata();
1042 let transcoder = ContractMessageTranscoder::new(metadata);
1043
1044 let encoded = transcoder.encode("set_name", [r#""Alice""#])?;
1045 let encoded_args = &encoded[4..];
1046
1047 let expected = "Alice".to_string().encode();
1048 assert_eq!(expected, encoded_args);
1049 Ok(())
1050 }
1051
1052 #[test]
1053 fn encode_string_unquoted_simple() -> Result<()> {
1054 let metadata = generate_metadata();
1056 let transcoder = ContractMessageTranscoder::new(metadata);
1057
1058 let encoded = transcoder.encode("set_name", ["Alice"])?;
1059 let encoded_args = &encoded[4..];
1060
1061 let expected = "Alice".to_string().encode();
1062 assert_eq!(expected, encoded_args);
1063 Ok(())
1064 }
1065
1066 #[test]
1067 fn encode_string_with_spaces() -> Result<()> {
1068 let metadata = generate_metadata();
1071 let transcoder = ContractMessageTranscoder::new(metadata);
1072
1073 let encoded = transcoder.encode("set_name", ["my string"])?;
1074 let encoded_args = &encoded[4..];
1075
1076 let expected = "my string".to_string().encode();
1077 assert_eq!(expected, encoded_args);
1078 Ok(())
1079 }
1080
1081 #[test]
1082 fn encode_string_with_special_chars() -> Result<()> {
1083 let metadata = generate_metadata();
1085 let transcoder = ContractMessageTranscoder::new(metadata);
1086
1087 let test_string = "Hello, World! 123 @#$%";
1088 let encoded = transcoder.encode("set_name", [test_string])?;
1089 let encoded_args = &encoded[4..];
1090
1091 let expected = test_string.to_string().encode();
1092 assert_eq!(expected, encoded_args);
1093 Ok(())
1094 }
1095
1096 #[test]
1097 fn encode_empty_string() -> Result<()> {
1098 let metadata = generate_metadata();
1100 let transcoder = ContractMessageTranscoder::new(metadata);
1101
1102 let encoded = transcoder.encode("set_name", [""])?;
1103 let encoded_args = &encoded[4..];
1104
1105 let expected = "".to_string().encode();
1106 assert_eq!(expected, encoded_args);
1107 Ok(())
1108 }
1109
1110 #[test]
1111 fn encode_string_numbers_as_string() -> Result<()> {
1112 let metadata = generate_metadata();
1114 let transcoder = ContractMessageTranscoder::new(metadata);
1115
1116 let encoded = transcoder.encode("set_name", ["12345"])?;
1117 let encoded_args = &encoded[4..];
1118
1119 let expected = "12345".to_string().encode();
1121 assert_eq!(expected, encoded_args);
1122 Ok(())
1123 }
1124}