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