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