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)]
566mod tests {
567 use super::*;
568 use crate::scon::Hex;
569 use ink_env::{
570 DefaultEnvironment,
571 Environment,
572 };
573 use primitive_types::H256;
574 use scale::Encode;
575 use scon::Value;
576 use std::str::FromStr;
577
578 #[allow(clippy::extra_unused_lifetimes, unexpected_cfgs, non_local_definitions)]
579 #[ink::contract]
580 pub mod transcode {
581 #[ink(storage)]
582 pub struct Transcode {
583 value: bool,
584 }
585
586 #[ink(event)]
587 pub struct Event1 {
588 #[ink(topic)]
589 name: Hash,
590 #[ink(topic)]
591 from: AccountId,
592 }
593
594 impl Transcode {
595 #[ink(constructor)]
596 pub fn new(init_value: bool) -> Self {
597 Self { value: init_value }
598 }
599
600 #[ink(constructor)]
601 pub fn default() -> Self {
602 Self::new(Default::default())
603 }
604
605 #[ink(message)]
606 pub fn flip(&mut self) {
607 self.value = !self.value;
608 }
609
610 #[ink(message)]
611 pub fn get(&self) -> bool {
612 self.value
613 }
614
615 #[ink(message)]
616 pub fn get_complex(
617 &self,
618 ) -> (u32, ink::H160, ink::H256, ink::U256, AccountId) {
619 (
620 32u32,
621 self.env().address(),
622 self.env().own_code_hash(),
623 ink::U256::one(),
625 AccountId::from([0x17; 32]),
626 )
627 }
628 #[ink(message)]
638 pub fn set_account_id(&self, account_id: AccountId) {
639 let _ = account_id;
640 }
641
642 #[ink(message)]
643 pub fn set_account_ids_vec(&self, account_ids: Vec<AccountId>) {
644 let _ = account_ids;
645 }
646
647 #[ink(message)]
648 pub fn primitive_vec_args(&self, args: Vec<u32>) {
649 let _ = args;
650 }
651
652 #[ink(message)]
653 pub fn uint_args(
654 &self,
655 _u8: u8,
656 _u16: u16,
657 _u32: u32,
658 _u64: u64,
659 _u128: u128,
660 ) {
661 }
662
663 #[ink(message)]
664 pub fn uint_array_args(&self, arr: [u8; 4]) {
665 let _ = arr;
666 }
667
668 #[ink(message)]
669 pub fn h160(&self, addr: ink::H160) {
670 let _ = addr;
671 }
672
673 #[ink(message)]
674 pub fn set_name(&self, _name: String) {}
675 }
676 }
677
678 fn generate_metadata() -> InkProject {
679 unsafe extern "Rust" {
680 fn __ink_generate_metadata() -> InkProject;
681 }
682
683 unsafe { __ink_generate_metadata() }
684 }
685
686 #[test]
687 fn encode_single_primitive_arg() -> Result<()> {
688 let metadata = generate_metadata();
689 let transcoder = ContractMessageTranscoder::new(metadata);
690
691 let encoded = transcoder.encode("new", ["true"])?;
692 let encoded_args = &encoded[4..];
694
695 assert_eq!(true.encode(), encoded_args);
696 Ok(())
697 }
698
699 #[test]
700 fn encode_misspelled_arg() {
701 let metadata = generate_metadata();
702 let transcoder = ContractMessageTranscoder::new(metadata);
703 assert_eq!(
704 transcoder.encode("fip", ["true"]).unwrap_err().to_string(),
705 "No constructor or message with the name 'fip' found.\nDid you mean 'flip'?"
706 );
707 }
708
709 #[test]
710 fn encode_mismatching_args_length() {
711 let metadata = generate_metadata();
712 let transcoder = ContractMessageTranscoder::new(metadata);
713
714 let result: Result<Vec<u8>> = transcoder.encode("new", Vec::<&str>::new());
715 assert!(result.is_err(), "Should return an error");
716 assert_eq!(
717 result.unwrap_err().to_string(),
718 "Invalid number of input arguments: expected 1, 0 provided"
719 );
720
721 let result: Result<Vec<u8>> = transcoder.encode("new", ["true", "false"]);
722 assert!(result.is_err(), "Should return an error");
723 assert_eq!(
724 result.unwrap_err().to_string(),
725 "Invalid number of input arguments: expected 1, 2 provided"
726 );
727 }
728
729 #[test]
730 fn encode_account_id_custom_ss58_encoding() -> Result<()> {
731 let metadata = generate_metadata();
732 let transcoder = ContractMessageTranscoder::new(metadata);
733
734 let encoded = transcoder.encode(
735 "set_account_id",
736 ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"],
737 )?;
738
739 let encoded_args = &encoded[4..];
741
742 let expected =
743 AccountId32::from_str("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY")
744 .unwrap();
745 assert_eq!(expected.encode(), encoded_args);
746 Ok(())
747 }
748
749 #[test]
750 fn encode_account_ids_vec_args() -> Result<()> {
751 let metadata = generate_metadata();
752 let transcoder = ContractMessageTranscoder::new(metadata);
753
754 let encoded = transcoder.encode(
755 "set_account_ids_vec",
756 ["[5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY, 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty]"],
757 )?;
758
759 let encoded_args = &encoded[4..];
761
762 let expected = vec![
763 AccountId32::from_str("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY")
764 .unwrap(),
765 AccountId32::from_str("5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty")
766 .unwrap(),
767 ];
768 assert_eq!(expected.encode(), encoded_args);
769 Ok(())
770 }
771
772 #[test]
773 fn encode_primitive_vec_args() -> Result<()> {
774 let metadata = generate_metadata();
775 let transcoder = ContractMessageTranscoder::new(metadata);
776
777 let encoded = transcoder.encode("primitive_vec_args", ["[1, 2]"])?;
778
779 let encoded_args = &encoded[4..];
781
782 let expected = vec![1, 2];
783 assert_eq!(expected.encode(), encoded_args);
784 Ok(())
785 }
786
787 #[test]
788 fn encode_uint_hex_literals() -> Result<()> {
789 let metadata = generate_metadata();
790 let transcoder = ContractMessageTranscoder::new(metadata);
791
792 let encoded = transcoder.encode(
793 "uint_args",
794 [
795 "0x00",
796 "0xDEAD",
797 "0xDEADBEEF",
798 "0xDEADBEEF12345678",
799 "0xDEADBEEF0123456789ABCDEF01234567",
800 ],
801 )?;
802
803 let encoded_args = &encoded[4..];
805
806 let expected = (
807 0x00u8,
808 0xDEADu16,
809 0xDEADBEEFu32,
810 0xDEADBEEF12345678u64,
811 0xDEADBEEF0123456789ABCDEF01234567u128,
812 );
813 assert_eq!(expected.encode(), encoded_args);
814 Ok(())
815 }
816
817 #[test]
818 fn encode_uint_arr_hex_literals() -> Result<()> {
819 let metadata = generate_metadata();
820 let transcoder = ContractMessageTranscoder::new(metadata);
821
822 let encoded =
823 transcoder.encode("uint_array_args", ["[0xDE, 0xAD, 0xBE, 0xEF]"])?;
824
825 let encoded_args = &encoded[4..];
827
828 let expected: [u8; 4] = [0xDE, 0xAD, 0xBE, 0xEF];
829 assert_eq!(expected.encode(), encoded_args);
830 Ok(())
831 }
832
833 #[test]
834 #[should_panic(
835 expected = "Error: You are attempting to transcode a shortened hex value: `\"0xbc3f…f58a\"`"
836 )]
837 fn encode_must_panic_on_shortened_hex() {
838 let metadata = generate_metadata();
839 let transcoder = ContractMessageTranscoder::new(metadata);
840
841 let _encoded = transcoder.encode("h160", ["0xbc3f…f58a"]);
842 }
843
844 #[test]
845 fn decode_complex_return() {
846 let metadata = generate_metadata();
847 let transcoder = ContractMessageTranscoder::new(metadata);
848
849 let addr: ink::H160 = ink::H160::from([0x42; 20]);
850 let account_id: AccountId32 = AccountId32::from([0x13; 32]);
851 let _hash: [u8; 32] = [0xAB; 32];
852 let h256: ink::H256 = ink::H256::from([0x17; 32]);
853 let value: ink::U256 = ink::U256::one();
855
856 let encoded = Result::<
857 (u32, ink::H160, ink::H256, ink::U256, AccountId32),
858 ink::primitives::LangError,
859 >::Ok((32, addr, h256, value, account_id))
860 .encode();
861
862 let decoded = transcoder
863 .decode_message_return("get_complex", &mut &encoded[..])
864 .unwrap_or_else(|e| panic!("Error decoding return value {e}"));
865
866 let expected = Value::Tuple(Tuple::new(
867 "Ok".into(),
868 [
869 Value::Tuple(Tuple::new(
870 None,
871 [
872 Value::UInt(32),
873 Value::Hex(Hex::from_str("0x4242424242424242424242424242424242424242").unwrap()),
874 Value::Hex(Hex::from_str("0x1717171717171717171717171717171717171717171717171717171717171717").unwrap()),
875 Value::Literal("1".to_string()),
876 Value::Literal("5CViS5pKamF1VbJ9tmQKPNDpLpJaBCfpPw2m49UzQ8zgiDGT".to_string()),
877 ]
878 .into_iter().collect()
879 ))
880 ]
881 .into_iter().collect(),
882 ));
883 assert_eq!(expected, decoded);
884 }
885
886 #[test]
887 fn decode_primitive_return() {
888 let metadata = generate_metadata();
889 let transcoder = ContractMessageTranscoder::new(metadata);
890
891 let encoded = Result::<bool, ink::primitives::LangError>::Ok(true).encode();
892 let decoded = transcoder
893 .decode_message_return("get", &mut &encoded[..])
894 .unwrap_or_else(|e| panic!("Error decoding return value {e}"));
895
896 let expected = Value::Tuple(Tuple::new(
897 "Ok".into(),
898 [Value::Bool(true)].into_iter().collect(),
899 ));
900 assert_eq!(expected, decoded);
901 }
902
903 #[test]
904 fn decode_lang_error() {
905 use ink::primitives::LangError;
906
907 let metadata = generate_metadata();
908 let transcoder = ContractMessageTranscoder::new(metadata);
909
910 let encoded =
911 Result::<bool, LangError>::Err(LangError::CouldNotReadInput).encode();
912 let decoded = transcoder
913 .decode_message_return("get", &mut &encoded[..])
914 .unwrap_or_else(|e| panic!("Error decoding return value {e}"));
915
916 let expected = Value::Tuple(Tuple::new(
917 "Err".into(),
918 [Value::Tuple(Tuple::new(
919 Some("CouldNotReadInput"),
920 Vec::new(),
921 ))]
922 .to_vec(),
923 ));
924 assert_eq!(expected, decoded);
925 }
926
927 #[test]
928 fn decode_contract_event() -> Result<()> {
929 let metadata = generate_metadata();
930 let transcoder = ContractMessageTranscoder::new(metadata);
931
932 let signature_topic: <DefaultEnvironment as Environment>::Hash =
933 <transcode::Event1 as ink::env::Event>::SIGNATURE_TOPIC
934 .unwrap()
935 .into();
936 let encoded = ([0u32; 8], [1u32; 8]).encode();
938 let encoded_bytes = encoded.encode();
940 let _ = transcoder
941 .decode_contract_event(&signature_topic, &mut &encoded_bytes[..])?;
942
943 Ok(())
946 }
947
948 #[test]
949 fn decode_hash_as_hex_encoded_string() -> Result<()> {
950 let metadata = generate_metadata();
951 let transcoder = ContractMessageTranscoder::new(metadata);
952
953 let hash = [
954 52u8, 40, 235, 225, 70, 245, 184, 36, 21, 218, 130, 114, 75, 207, 117, 240,
955 83, 118, 135, 56, 220, 172, 95, 131, 171, 125, 130, 167, 10, 15, 242, 222,
956 ];
957 let signature_topic: <DefaultEnvironment as Environment>::Hash =
958 <transcode::Event1 as ink::env::Event>::SIGNATURE_TOPIC
959 .unwrap()
960 .into();
961 let encoded = (hash, [0u32; 8]).encode();
963 let encoded_bytes = encoded.encode();
965 let decoded = transcoder
966 .decode_contract_event(&signature_topic, &mut &encoded_bytes[..])?;
967
968 if let Value::Map(ref map) = decoded {
969 let name_field = &map[&Value::String("name".into())];
970 if let Value::Hex(hex) = name_field {
971 assert_eq!(
972 &Hex::from_str(
973 "0x3428ebe146f5b82415da82724bcf75f053768738dcac5f83ab7d82a70a0ff2de"
974 )?,
975 hex
976 );
977 Ok(())
978 } else {
979 Err(anyhow::anyhow!(
980 "Expected a name field hash encoded as Hex value, was {name_field:?}"
981 ))
982 }
983 } else {
984 Err(anyhow::anyhow!(
985 "Expected a Value::Map for the decoded event"
986 ))
987 }
988 }
989
990 #[test]
991 fn decode_contract_message() -> Result<()> {
992 let metadata = generate_metadata();
993 let transcoder = ContractMessageTranscoder::new(metadata);
994
995 let encoded_bytes = hex::decode("633aa551").unwrap();
996 let _ = transcoder.decode_contract_message(&mut &encoded_bytes[..])?;
997
998 Ok(())
999 }
1000
1001 #[test]
1002 #[should_panic(
1003 expected = "input length was longer than expected by 1 byte(s).\nManaged to decode `flip` but `00` bytes were left unread"
1004 )]
1005 fn fail_decode_input_with_extra_bytes() {
1006 let metadata = generate_metadata();
1007 let transcoder = ContractMessageTranscoder::new(metadata);
1008
1009 let encoded_bytes = hex::decode("633aa55100").unwrap();
1010 let _ = transcoder
1011 .decode_contract_message(&mut &encoded_bytes[..])
1012 .unwrap();
1013 }
1014
1015 #[test]
1016 #[should_panic(
1017 expected = "input length was longer than expected by 2 byte(s).\nManaged to decode `Event1`, `name`, `from` but `0C10` bytes were left unread"
1018 )]
1019 fn fail_decode_contract_event_with_extra_bytes() {
1020 let metadata = generate_metadata();
1021 let transcoder = ContractMessageTranscoder::new(metadata);
1022
1023 let signature_topic: H256 =
1024 <transcode::Event1 as ink::env::Event>::SIGNATURE_TOPIC
1025 .unwrap()
1026 .into();
1027 let encoded = ([0u32; 8], [1u32; 8], [12u8, 16u8]).encode();
1029 let encoded_bytes = encoded.encode();
1031 let _ = transcoder
1032 .decode_contract_event(&signature_topic, &mut &encoded_bytes[..])
1033 .unwrap();
1034 }
1035
1036 #[test]
1037 fn encode_string_quoted_traditional() -> Result<()> {
1038 let metadata = generate_metadata();
1040 let transcoder = ContractMessageTranscoder::new(metadata);
1041
1042 let encoded = transcoder.encode("set_name", [r#""Alice""#])?;
1043 let encoded_args = &encoded[4..];
1044
1045 let expected = "Alice".to_string().encode();
1046 assert_eq!(expected, encoded_args);
1047 Ok(())
1048 }
1049
1050 #[test]
1051 fn encode_string_unquoted_simple() -> Result<()> {
1052 let metadata = generate_metadata();
1054 let transcoder = ContractMessageTranscoder::new(metadata);
1055
1056 let encoded = transcoder.encode("set_name", ["Alice"])?;
1057 let encoded_args = &encoded[4..];
1058
1059 let expected = "Alice".to_string().encode();
1060 assert_eq!(expected, encoded_args);
1061 Ok(())
1062 }
1063
1064 #[test]
1065 fn encode_string_with_spaces() -> Result<()> {
1066 let metadata = generate_metadata();
1069 let transcoder = ContractMessageTranscoder::new(metadata);
1070
1071 let encoded = transcoder.encode("set_name", ["my string"])?;
1072 let encoded_args = &encoded[4..];
1073
1074 let expected = "my string".to_string().encode();
1075 assert_eq!(expected, encoded_args);
1076 Ok(())
1077 }
1078
1079 #[test]
1080 fn encode_string_with_special_chars() -> Result<()> {
1081 let metadata = generate_metadata();
1083 let transcoder = ContractMessageTranscoder::new(metadata);
1084
1085 let test_string = "Hello, World! 123 @#$%";
1086 let encoded = transcoder.encode("set_name", [test_string])?;
1087 let encoded_args = &encoded[4..];
1088
1089 let expected = test_string.to_string().encode();
1090 assert_eq!(expected, encoded_args);
1091 Ok(())
1092 }
1093
1094 #[test]
1095 fn encode_empty_string() -> Result<()> {
1096 let metadata = generate_metadata();
1098 let transcoder = ContractMessageTranscoder::new(metadata);
1099
1100 let encoded = transcoder.encode("set_name", [""])?;
1101 let encoded_args = &encoded[4..];
1102
1103 let expected = "".to_string().encode();
1104 assert_eq!(expected, encoded_args);
1105 Ok(())
1106 }
1107
1108 #[test]
1109 fn encode_string_numbers_as_string() -> Result<()> {
1110 let metadata = generate_metadata();
1112 let transcoder = ContractMessageTranscoder::new(metadata);
1113
1114 let encoded = transcoder.encode("set_name", ["12345"])?;
1115 let encoded_args = &encoded[4..];
1116
1117 let expected = "12345".to_string().encode();
1119 assert_eq!(expected, encoded_args);
1120 Ok(())
1121 }
1122}