1#![allow(clippy::new_ret_no_self)]
16
17use crate::{
18 serde_hex,
19 utils::{
20 deserialize_from_byte_str,
21 serialize_as_byte_str,
22 trim_extra_whitespace,
23 },
24};
25#[cfg(not(feature = "std"))]
26use alloc::{
27 collections::BTreeMap,
28 format,
29 string::String,
30 vec,
31 vec::Vec,
32};
33use core::{
34 fmt::Display,
35 marker::PhantomData,
36};
37use scale_info::{
38 IntoPortable,
39 Registry,
40 TypeInfo,
41 form::{
42 Form,
43 MetaForm,
44 PortableForm,
45 },
46 meta_type,
47};
48use schemars::JsonSchema;
49use serde::{
50 Deserialize,
51 Serialize,
52 de::DeserializeOwned,
53};
54#[cfg(feature = "std")]
55use std::{
56 collections::BTreeMap,
57 hash::Hash,
58};
59
60#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
62#[serde(bound(
63 serialize = "F::Type: Serialize, F::String: Serialize",
64 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
65))]
66pub struct ContractSpec<F: Form = MetaForm>
67where
68 TypeSpec<F>: Default,
69{
70 constructors: Vec<ConstructorSpec<F>>,
72 messages: Vec<MessageSpec<F>>,
74 events: Vec<EventSpec<F>>,
76 docs: Vec<F::String>,
78 lang_error: TypeSpec<F>,
80 environment: EnvironmentSpec<F>,
82}
83
84impl IntoPortable for ContractSpec {
85 type Output = ContractSpec<PortableForm>;
86
87 fn into_portable(self, registry: &mut Registry) -> Self::Output {
88 ContractSpec {
89 constructors: self
90 .constructors
91 .into_iter()
92 .map(|constructor| constructor.into_portable(registry))
93 .collect::<Vec<_>>(),
94 messages: self
95 .messages
96 .into_iter()
97 .map(|msg| msg.into_portable(registry))
98 .collect::<Vec<_>>(),
99 events: self
100 .events
101 .into_iter()
102 .map(|event| event.into_portable(registry))
103 .collect::<Vec<_>>(),
104 docs: registry.map_into_portable(self.docs),
105 lang_error: self.lang_error.into_portable(registry),
106 environment: self.environment.into_portable(registry),
107 }
108 }
109}
110
111impl<F> ContractSpec<F>
112where
113 F: Form,
114 TypeSpec<F>: Default,
115{
116 pub fn constructors(&self) -> &[ConstructorSpec<F>] {
118 &self.constructors
119 }
120
121 pub fn messages(&self) -> &[MessageSpec<F>] {
123 &self.messages
124 }
125
126 pub fn events(&self) -> &[EventSpec<F>] {
128 &self.events
129 }
130
131 pub fn docs(&self) -> &[F::String] {
133 &self.docs
134 }
135
136 pub fn lang_error(&self) -> &TypeSpec<F> {
138 &self.lang_error
139 }
140 pub fn environment(&self) -> &EnvironmentSpec<F> {
142 &self.environment
143 }
144}
145
146pub enum Valid {}
148pub enum Invalid {}
150
151#[must_use]
152pub struct ContractSpecBuilder<F, S = Invalid>
153where
154 F: Form,
155 TypeSpec<F>: Default,
156{
157 spec: ContractSpec<F>,
159 marker: PhantomData<fn() -> S>,
161}
162
163impl<F> ContractSpecBuilder<F, Invalid>
164where
165 F: Form,
166 TypeSpec<F>: Default,
167{
168 pub fn constructors<C>(self, constructors: C) -> ContractSpecBuilder<F, Valid>
170 where
171 C: IntoIterator<Item = ConstructorSpec<F>>,
172 {
173 debug_assert!(self.spec.constructors.is_empty());
174 ContractSpecBuilder {
175 spec: ContractSpec {
176 constructors: constructors.into_iter().collect::<Vec<_>>(),
177 ..self.spec
178 },
179 marker: Default::default(),
180 }
181 }
182}
183
184impl<F, S> ContractSpecBuilder<F, S>
185where
186 F: Form,
187 TypeSpec<F>: Default,
188{
189 pub fn messages<M>(self, messages: M) -> Self
191 where
192 M: IntoIterator<Item = MessageSpec<F>>,
193 {
194 debug_assert!(self.spec.messages.is_empty());
195 Self {
196 spec: ContractSpec {
197 messages: messages.into_iter().collect::<Vec<_>>(),
198 ..self.spec
199 },
200 ..self
201 }
202 }
203
204 pub fn events<E>(self, events: E) -> Self
206 where
207 E: IntoIterator<Item = EventSpec<F>>,
208 {
209 debug_assert!(self.spec.events.is_empty());
210 Self {
211 spec: ContractSpec {
212 events: events.into_iter().collect::<Vec<_>>(),
213 ..self.spec
214 },
215 ..self
216 }
217 }
218
219 pub fn docs<D>(self, docs: D) -> Self
221 where
222 D: IntoIterator<Item = <F as Form>::String>,
223 {
224 debug_assert!(self.spec.docs.is_empty());
225 Self {
226 spec: ContractSpec {
227 docs: docs.into_iter().collect::<Vec<_>>(),
228 ..self.spec
229 },
230 ..self
231 }
232 }
233
234 pub fn lang_error(self, lang_error: TypeSpec<F>) -> Self {
236 Self {
237 spec: ContractSpec {
238 lang_error,
239 ..self.spec
240 },
241 ..self
242 }
243 }
244
245 pub fn environment(self, environment: EnvironmentSpec<F>) -> Self {
247 Self {
248 spec: ContractSpec {
249 environment,
250 ..self.spec
251 },
252 ..self
253 }
254 }
255}
256
257impl<F> ContractSpecBuilder<F, Valid>
258where
259 F: Form,
260 F::String: Display,
261 TypeSpec<F>: Default,
262{
263 #[allow(clippy::arithmetic_side_effects)] pub fn done(self) -> ContractSpec<F> {
266 assert!(
267 !self.spec.constructors.is_empty(),
268 "must have at least one constructor"
269 );
270 assert!(
271 !self.spec.messages.is_empty(),
272 "must have at least one message"
273 );
274 assert!(
275 self.spec.constructors.iter().filter(|c| c.default).count() < 2,
276 "only one default constructor is allowed"
277 );
278 assert!(
279 self.spec.messages.iter().filter(|m| m.default).count() < 2,
280 "only one default message is allowed"
281 );
282
283 const MAX_TOPICS: usize = 4;
284 let events_exceeding_max_topics_limit = self
285 .spec
286 .events
287 .iter()
288 .filter_map(|e| {
289 let signature_topic = if e.signature_topic.is_some() { 1 } else { 0 };
290 let topics_count =
291 signature_topic + e.args.iter().filter(|a| a.indexed).count();
292 if topics_count > MAX_TOPICS {
293 Some(format!(
294 "`{}::{}` ({} topics)",
295 e.module_path, e.label, topics_count
296 ))
297 } else {
298 None
299 }
300 })
301 .collect::<Vec<_>>();
302 assert!(
303 events_exceeding_max_topics_limit.is_empty(),
304 "maximum of {MAX_TOPICS} event topics exceeded: {}",
305 events_exceeding_max_topics_limit.join(", ")
306 );
307
308 let mut signature_topics: BTreeMap<Vec<u8>, Vec<String>> = BTreeMap::new();
309 for e in self.spec.events.iter() {
310 if let Some(signature_topic) = &e.signature_topic {
311 signature_topics
312 .entry(signature_topic.bytes.clone())
313 .or_default()
314 .push(format!("`{}::{}`", e.module_path, e.label));
315 }
316 }
317 let signature_topic_collisions = signature_topics
318 .iter()
319 .filter_map(|(_, topics)| {
320 if topics.len() > 1 {
321 Some(format!(
322 "event signature topic collision: {}",
323 topics.join(", ")
324 ))
325 } else {
326 None
327 }
328 })
329 .collect::<Vec<_>>();
330 assert!(
331 signature_topic_collisions.is_empty(),
332 "{}",
333 signature_topic_collisions.join("\n")
334 );
335
336 self.spec
337 }
338}
339
340impl<F> ContractSpec<F>
341where
342 F: Form,
343 TypeSpec<F>: Default,
344 EnvironmentSpec<F>: Default,
345{
346 pub fn new() -> ContractSpecBuilder<F, Invalid> {
348 ContractSpecBuilder {
349 spec: Self {
350 constructors: Vec::new(),
351 messages: Vec::new(),
352 events: Vec::new(),
353 docs: Vec::new(),
354 lang_error: Default::default(),
355 environment: Default::default(),
356 },
357 marker: PhantomData,
358 }
359 }
360}
361
362#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
364#[serde(bound(
365 serialize = "F::Type: Serialize, F::String: Serialize",
366 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned",
367))]
368#[serde(rename_all = "camelCase")]
369pub struct ConstructorSpec<F: Form = MetaForm> {
370 pub label: F::String,
375 pub selector: Selector,
377 pub payable: bool,
379 pub args: Vec<MessageParamSpec<F>>,
381 pub return_type: ReturnTypeSpec<F>,
383 pub docs: Vec<F::String>,
385 default: bool,
387}
388
389impl IntoPortable for ConstructorSpec {
390 type Output = ConstructorSpec<PortableForm>;
391
392 fn into_portable(self, registry: &mut Registry) -> Self::Output {
393 ConstructorSpec {
394 label: self.label.to_string(),
395 selector: self.selector,
396 payable: self.payable,
397 args: self
398 .args
399 .into_iter()
400 .map(|arg| arg.into_portable(registry))
401 .collect::<Vec<_>>(),
402 return_type: self.return_type.into_portable(registry),
403 docs: self.docs.into_iter().map(|s| s.into()).collect(),
404 default: self.default,
405 }
406 }
407}
408
409impl<F> ConstructorSpec<F>
410where
411 F: Form,
412{
413 pub fn label(&self) -> &F::String {
418 &self.label
419 }
420
421 pub fn selector(&self) -> &Selector {
423 &self.selector
424 }
425
426 pub fn payable(&self) -> bool {
428 self.payable
429 }
430
431 pub fn args(&self) -> &[MessageParamSpec<F>] {
433 &self.args
434 }
435
436 pub fn return_type(&self) -> &ReturnTypeSpec<F> {
438 &self.return_type
439 }
440
441 pub fn docs(&self) -> &[F::String] {
443 &self.docs
444 }
445
446 pub fn default(&self) -> bool {
447 self.default
448 }
449}
450
451#[allow(clippy::type_complexity)]
459#[must_use]
460pub struct ConstructorSpecBuilder<F: Form, Selector, IsPayable, Returns> {
461 spec: ConstructorSpec<F>,
462 marker: PhantomData<fn() -> (Selector, IsPayable, Returns)>,
463}
464
465impl<F> ConstructorSpec<F>
466where
467 F: Form,
468 TypeSpec<F>: Default,
469{
470 pub fn from_label(
472 label: <F as Form>::String,
473 ) -> ConstructorSpecBuilder<
474 F,
475 Missing<state::Selector>,
476 Missing<state::IsPayable>,
477 Missing<state::Returns>,
478 > {
479 ConstructorSpecBuilder {
480 spec: Self {
481 label,
482 selector: Selector::default(),
483 payable: Default::default(),
484 args: Vec::new(),
485 return_type: ReturnTypeSpec::new(TypeSpec::default()),
486 docs: Vec::new(),
487 default: false,
488 },
489 marker: PhantomData,
490 }
491 }
492}
493
494impl<F, P, R> ConstructorSpecBuilder<F, Missing<state::Selector>, P, R>
495where
496 F: Form,
497{
498 pub fn selector(
500 self,
501 selector: [u8; 4],
502 ) -> ConstructorSpecBuilder<F, state::Selector, P, R> {
503 ConstructorSpecBuilder {
504 spec: ConstructorSpec {
505 selector: selector.into(),
506 ..self.spec
507 },
508 marker: PhantomData,
509 }
510 }
511}
512
513impl<F, S, R> ConstructorSpecBuilder<F, S, Missing<state::IsPayable>, R>
514where
515 F: Form,
516{
517 pub fn payable(
519 self,
520 is_payable: bool,
521 ) -> ConstructorSpecBuilder<F, S, state::IsPayable, R> {
522 ConstructorSpecBuilder {
523 spec: ConstructorSpec {
524 payable: is_payable,
525 ..self.spec
526 },
527 marker: PhantomData,
528 }
529 }
530}
531
532impl<F, S, P> ConstructorSpecBuilder<F, S, P, Missing<state::Returns>>
533where
534 F: Form,
535{
536 pub fn returns(
538 self,
539 return_type: ReturnTypeSpec<F>,
540 ) -> ConstructorSpecBuilder<F, S, P, state::Returns> {
541 ConstructorSpecBuilder {
542 spec: ConstructorSpec {
543 return_type,
544 ..self.spec
545 },
546 marker: PhantomData,
547 }
548 }
549}
550
551impl<F, S, P, R> ConstructorSpecBuilder<F, S, P, R>
552where
553 F: Form,
554{
555 pub fn args<A>(self, args: A) -> Self
557 where
558 A: IntoIterator<Item = MessageParamSpec<F>>,
559 {
560 let mut this = self;
561 debug_assert!(this.spec.args.is_empty());
562 this.spec.args = args.into_iter().collect::<Vec<_>>();
563 this
564 }
565
566 pub fn docs<'a, D>(self, docs: D) -> Self
568 where
569 D: IntoIterator<Item = &'a str>,
570 F::String: From<&'a str>,
571 {
572 let mut this = self;
573 debug_assert!(this.spec.docs.is_empty());
574 this.spec.docs = docs
575 .into_iter()
576 .map(|s| trim_extra_whitespace(s).into())
577 .collect::<Vec<_>>();
578 this
579 }
580
581 pub fn default(self, default: bool) -> Self {
583 ConstructorSpecBuilder {
584 spec: ConstructorSpec {
585 default,
586 ..self.spec
587 },
588 marker: PhantomData,
589 }
590 }
591}
592
593impl<F> ConstructorSpecBuilder<F, state::Selector, state::IsPayable, state::Returns>
594where
595 F: Form,
596{
597 pub fn done(self) -> ConstructorSpec<F> {
599 self.spec
600 }
601}
602
603#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
605#[serde(bound(
606 serialize = "F::Type: Serialize, F::String: Serialize",
607 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
608))]
609#[serde(rename_all = "camelCase")]
610pub struct MessageSpec<F: Form = MetaForm> {
611 label: F::String,
616 selector: Selector,
618 mutates: bool,
620 payable: bool,
622 args: Vec<MessageParamSpec<F>>,
624 return_type: ReturnTypeSpec<F>,
626 docs: Vec<F::String>,
628 default: bool,
630}
631
632pub struct Missing<S>(PhantomData<fn() -> S>);
635
636mod state {
637 pub struct Selector;
642 pub struct Mutates;
644 pub struct IsPayable;
646 pub struct Returns;
648 pub struct AccountId;
650 pub struct Balance;
652 pub struct Hash;
654 pub struct Timestamp;
656 pub struct BlockNumber;
658 pub struct NativeToEthRatio;
660 pub struct BufferSize;
662}
663
664impl<F> MessageSpec<F>
665where
666 F: Form,
667 TypeSpec<F>: Default,
668{
669 pub fn from_label(
671 label: <F as Form>::String,
672 ) -> MessageSpecBuilder<
673 F,
674 Missing<state::Selector>,
675 Missing<state::Mutates>,
676 Missing<state::IsPayable>,
677 Missing<state::Returns>,
678 > {
679 MessageSpecBuilder {
680 spec: Self {
681 label,
682 selector: Selector::default(),
683 mutates: false,
684 payable: false,
685 args: Vec::new(),
686 return_type: ReturnTypeSpec::new(TypeSpec::default()),
687 docs: Vec::new(),
688 default: false,
689 },
690 marker: PhantomData,
691 }
692 }
693}
694
695impl<F> MessageSpec<F>
696where
697 F: Form,
698{
699 pub fn label(&self) -> &F::String {
704 &self.label
705 }
706
707 pub fn selector(&self) -> &Selector {
709 &self.selector
710 }
711
712 pub fn mutates(&self) -> bool {
714 self.mutates
715 }
716
717 pub fn payable(&self) -> bool {
719 self.payable
720 }
721
722 pub fn args(&self) -> &[MessageParamSpec<F>] {
724 &self.args
725 }
726
727 pub fn return_type(&self) -> &ReturnTypeSpec<F> {
729 &self.return_type
730 }
731
732 pub fn docs(&self) -> &[F::String] {
734 &self.docs
735 }
736
737 pub fn default(&self) -> bool {
738 self.default
739 }
740}
741
742#[allow(clippy::type_complexity)]
750#[must_use]
751pub struct MessageSpecBuilder<F, Selector, Mutates, IsPayable, Returns>
752where
753 F: Form,
754{
755 spec: MessageSpec<F>,
756 marker: PhantomData<fn() -> (Selector, Mutates, IsPayable, Returns)>,
757}
758
759impl<F, M, P, R> MessageSpecBuilder<F, Missing<state::Selector>, M, P, R>
760where
761 F: Form,
762{
763 pub fn selector(
765 self,
766 selector: [u8; 4],
767 ) -> MessageSpecBuilder<F, state::Selector, M, P, R> {
768 MessageSpecBuilder {
769 spec: MessageSpec {
770 selector: selector.into(),
771 ..self.spec
772 },
773 marker: PhantomData,
774 }
775 }
776}
777
778impl<F, S, P, R> MessageSpecBuilder<F, S, Missing<state::Mutates>, P, R>
779where
780 F: Form,
781{
782 pub fn mutates(
785 self,
786 mutates: bool,
787 ) -> MessageSpecBuilder<F, S, state::Mutates, P, R> {
788 MessageSpecBuilder {
789 spec: MessageSpec {
790 mutates,
791 ..self.spec
792 },
793 marker: PhantomData,
794 }
795 }
796}
797
798impl<F, S, M, R> MessageSpecBuilder<F, S, M, Missing<state::IsPayable>, R>
799where
800 F: Form,
801{
802 pub fn payable(
804 self,
805 is_payable: bool,
806 ) -> MessageSpecBuilder<F, S, M, state::IsPayable, R> {
807 MessageSpecBuilder {
808 spec: MessageSpec {
809 payable: is_payable,
810 ..self.spec
811 },
812 marker: PhantomData,
813 }
814 }
815}
816
817impl<F, M, S, P> MessageSpecBuilder<F, S, M, P, Missing<state::Returns>>
818where
819 F: Form,
820{
821 pub fn returns(
823 self,
824 return_type: ReturnTypeSpec<F>,
825 ) -> MessageSpecBuilder<F, S, M, P, state::Returns> {
826 MessageSpecBuilder {
827 spec: MessageSpec {
828 return_type,
829 ..self.spec
830 },
831 marker: PhantomData,
832 }
833 }
834}
835
836impl<F, S, M, P, R> MessageSpecBuilder<F, S, M, P, R>
837where
838 F: Form,
839{
840 pub fn args<A>(self, args: A) -> Self
842 where
843 A: IntoIterator<Item = MessageParamSpec<F>>,
844 {
845 let mut this = self;
846 debug_assert!(this.spec.args.is_empty());
847 this.spec.args = args.into_iter().collect::<Vec<_>>();
848 this
849 }
850
851 pub fn docs<D>(self, docs: D) -> Self
853 where
854 D: IntoIterator<Item = <F as Form>::String>,
855 {
856 let mut this = self;
857 debug_assert!(this.spec.docs.is_empty());
858 this.spec.docs = docs.into_iter().collect::<Vec<_>>();
859 this
860 }
861
862 pub fn default(self, default: bool) -> Self {
864 MessageSpecBuilder {
865 spec: MessageSpec {
866 default,
867 ..self.spec
868 },
869 marker: PhantomData,
870 }
871 }
872}
873
874impl<F>
875 MessageSpecBuilder<
876 F,
877 state::Selector,
878 state::Mutates,
879 state::IsPayable,
880 state::Returns,
881 >
882where
883 F: Form,
884{
885 pub fn done(self) -> MessageSpec<F> {
887 self.spec
888 }
889}
890
891impl IntoPortable for MessageSpec {
892 type Output = MessageSpec<PortableForm>;
893
894 fn into_portable(self, registry: &mut Registry) -> Self::Output {
895 MessageSpec {
896 label: self.label.to_string(),
897 selector: self.selector,
898 mutates: self.mutates,
899 payable: self.payable,
900 default: self.default,
901 args: self
902 .args
903 .into_iter()
904 .map(|arg| arg.into_portable(registry))
905 .collect::<Vec<_>>(),
906 return_type: self.return_type.into_portable(registry),
907 docs: self.docs.into_iter().map(|s| s.into()).collect(),
908 }
909 }
910}
911
912#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
914#[serde(bound(
915 serialize = "F::Type: Serialize, F::String: Serialize",
916 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
917))]
918pub struct EventSpec<F: Form = MetaForm> {
919 label: F::String,
921 module_path: F::String,
923 signature_topic: Option<SignatureTopic>,
925 args: Vec<EventParamSpec<F>>,
927 docs: Vec<F::String>,
929}
930
931#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
933#[serde(transparent)]
934pub struct SignatureTopic {
935 #[serde(
936 serialize_with = "serialize_as_byte_str",
937 deserialize_with = "deserialize_from_byte_str"
938 )]
939 bytes: Vec<u8>,
940}
941
942impl<T> From<T> for SignatureTopic
943where
944 T: AsRef<[u8]>,
945{
946 fn from(bytes: T) -> Self {
947 SignatureTopic {
948 bytes: bytes.as_ref().to_vec(),
949 }
950 }
951}
952
953impl SignatureTopic {
954 pub fn as_bytes(&self) -> &[u8] {
956 &self.bytes
957 }
958}
959
960#[must_use]
962pub struct EventSpecBuilder<F>
963where
964 F: Form,
965{
966 spec: EventSpec<F>,
967}
968
969impl<F> EventSpecBuilder<F>
970where
971 F: Form,
972{
973 pub fn module_path<'a>(self, path: &'a str) -> Self
975 where
976 F::String: From<&'a str>,
977 {
978 let mut this = self;
979 this.spec.module_path = path.into();
980 this
981 }
982
983 pub fn args<A>(self, args: A) -> Self
985 where
986 A: IntoIterator<Item = EventParamSpec<F>>,
987 {
988 let mut this = self;
989 debug_assert!(this.spec.args.is_empty());
990 this.spec.args = args.into_iter().collect::<Vec<_>>();
991 this
992 }
993
994 pub fn signature_topic<T>(self, topic: Option<T>) -> Self
996 where
997 T: AsRef<[u8]>,
998 {
999 let mut this = self;
1000 debug_assert!(this.spec.signature_topic.is_none());
1001 this.spec.signature_topic = topic.as_ref().map(SignatureTopic::from);
1002 this
1003 }
1004
1005 pub fn docs<'a, D>(self, docs: D) -> Self
1007 where
1008 D: IntoIterator<Item = &'a str>,
1009 F::String: From<&'a str>,
1010 {
1011 let mut this = self;
1012 debug_assert!(this.spec.docs.is_empty());
1013 this.spec.docs = docs
1014 .into_iter()
1015 .map(|s| trim_extra_whitespace(s).into())
1016 .collect::<Vec<_>>();
1017 this
1018 }
1019
1020 pub fn done(self) -> EventSpec<F> {
1022 self.spec
1023 }
1024}
1025
1026impl IntoPortable for EventSpec {
1027 type Output = EventSpec<PortableForm>;
1028
1029 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1030 EventSpec {
1031 label: self.label.to_string(),
1032 module_path: self.module_path.to_string(),
1033 signature_topic: self.signature_topic,
1034 args: self
1035 .args
1036 .into_iter()
1037 .map(|arg| arg.into_portable(registry))
1038 .collect::<Vec<_>>(),
1039 docs: self.docs.into_iter().map(|s| s.into()).collect(),
1040 }
1041 }
1042}
1043
1044impl<F> EventSpec<F>
1045where
1046 F: Form,
1047 F::String: Default,
1048{
1049 pub fn new(label: <F as Form>::String) -> EventSpecBuilder<F> {
1051 EventSpecBuilder {
1052 spec: Self {
1053 label,
1054 module_path: Default::default(),
1055 signature_topic: None,
1056 args: Vec::new(),
1057 docs: Vec::new(),
1058 },
1059 }
1060 }
1061}
1062
1063impl<F> EventSpec<F>
1064where
1065 F: Form,
1066{
1067 pub fn label(&self) -> &F::String {
1069 &self.label
1070 }
1071
1072 pub fn args(&self) -> &[EventParamSpec<F>] {
1074 &self.args
1075 }
1076
1077 pub fn signature_topic(&self) -> Option<&SignatureTopic> {
1079 self.signature_topic.as_ref()
1080 }
1081
1082 pub fn docs(&self) -> &[F::String] {
1084 &self.docs
1085 }
1086}
1087
1088#[cfg_attr(feature = "std", derive(Hash))]
1090#[derive(Debug, Default, PartialEq, Eq, derive_more::From, JsonSchema)]
1091pub struct Selector(#[schemars(with = "String")] [u8; 4]);
1092
1093impl serde::Serialize for Selector {
1094 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1095 where
1096 S: serde::Serializer,
1097 {
1098 serde_hex::serialize(&self.0, serializer)
1099 }
1100}
1101
1102impl<'de> serde::Deserialize<'de> for Selector {
1103 fn deserialize<D>(d: D) -> Result<Self, D::Error>
1104 where
1105 D: serde::Deserializer<'de>,
1106 {
1107 let mut arr = [0; 4];
1108 serde_hex::deserialize_check_len(d, serde_hex::ExpectedLen::Exact(&mut arr[..]))?;
1109 Ok(arr.into())
1110 }
1111}
1112
1113impl Selector {
1114 pub fn new<T>(bytes: T) -> Self
1116 where
1117 T: Into<[u8; 4]>,
1118 {
1119 Self(bytes.into())
1120 }
1121
1122 pub fn to_bytes(&self) -> &[u8] {
1124 &self.0
1125 }
1126}
1127
1128pub type DisplayName<F> = scale_info::Path<F>;
1146
1147#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1165#[serde(bound(
1166 serialize = "F::Type: Serialize, F::String: Serialize",
1167 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1168))]
1169#[serde(rename_all = "camelCase")]
1170pub struct TypeSpec<F: Form = MetaForm> {
1171 #[serde(rename = "type")]
1173 ty: F::Type,
1174 display_name: DisplayName<F>,
1176}
1177
1178impl Default for TypeSpec<MetaForm> {
1179 fn default() -> Self {
1180 TypeSpec::of_type::<()>()
1181 }
1182}
1183
1184impl Default for TypeSpec<PortableForm> {
1185 fn default() -> Self {
1186 Self {
1187 ty: u32::default().into(),
1188 display_name: Default::default(),
1189 }
1190 }
1191}
1192
1193impl IntoPortable for TypeSpec {
1194 type Output = TypeSpec<PortableForm>;
1195
1196 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1197 TypeSpec {
1198 ty: registry.register_type(&self.ty),
1199 display_name: self.display_name.into_portable(registry),
1200 }
1201 }
1202}
1203
1204impl TypeSpec {
1205 pub fn with_name_str<T>(display_name: &'static str) -> Self
1217 where
1218 T: TypeInfo + 'static,
1219 {
1220 Self::with_name_segs::<T, _>(display_name.split("::"))
1221 }
1222
1223 pub fn with_name_segs<T, S>(segments: S) -> Self
1236 where
1237 T: TypeInfo + 'static,
1238 S: IntoIterator<Item = &'static str>,
1239 {
1240 Self {
1241 ty: meta_type::<T>(),
1242 display_name: DisplayName::from_segments(segments)
1243 .unwrap_or_else(|err| panic!("display name is invalid: {err:?}")),
1244 }
1245 }
1246
1247 pub fn of_type<T>() -> Self
1255 where
1256 T: TypeInfo + 'static,
1257 {
1258 Self {
1259 ty: meta_type::<T>(),
1260 display_name: DisplayName::default(),
1261 }
1262 }
1263}
1264
1265impl<F> TypeSpec<F>
1266where
1267 F: Form,
1268{
1269 pub fn ty(&self) -> &F::Type {
1271 &self.ty
1272 }
1273
1274 pub fn display_name(&self) -> &DisplayName<F> {
1276 &self.display_name
1277 }
1278
1279 pub fn new(ty: <F as Form>::Type, display_name: DisplayName<F>) -> Self {
1281 Self { ty, display_name }
1282 }
1283}
1284
1285#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1287#[serde(bound(
1288 serialize = "F::Type: Serialize, F::String: Serialize",
1289 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1290))]
1291pub struct EventParamSpec<F: Form = MetaForm> {
1292 label: F::String,
1294 indexed: bool,
1296 #[serde(rename = "type")]
1298 ty: TypeSpec<F>,
1299 docs: Vec<F::String>,
1301}
1302
1303impl IntoPortable for EventParamSpec {
1304 type Output = EventParamSpec<PortableForm>;
1305
1306 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1307 EventParamSpec {
1308 label: self.label.to_string(),
1309 indexed: self.indexed,
1310 ty: self.ty.into_portable(registry),
1311 docs: self.docs.into_iter().map(|s| s.into()).collect(),
1312 }
1313 }
1314}
1315
1316impl<F> EventParamSpec<F>
1317where
1318 F: Form,
1319 TypeSpec<F>: Default,
1320{
1321 pub fn new(label: F::String) -> EventParamSpecBuilder<F> {
1323 EventParamSpecBuilder {
1324 spec: Self {
1325 label,
1326 indexed: false,
1328 ty: Default::default(),
1330 docs: vec![],
1332 },
1333 }
1334 }
1335 pub fn label(&self) -> &F::String {
1337 &self.label
1338 }
1339
1340 pub fn indexed(&self) -> bool {
1342 self.indexed
1343 }
1344
1345 pub fn ty(&self) -> &TypeSpec<F> {
1347 &self.ty
1348 }
1349
1350 pub fn docs(&self) -> &[F::String] {
1352 &self.docs
1353 }
1354}
1355
1356#[must_use]
1358pub struct EventParamSpecBuilder<F>
1359where
1360 F: Form,
1361{
1362 spec: EventParamSpec<F>,
1364}
1365
1366impl<F> EventParamSpecBuilder<F>
1367where
1368 F: Form,
1369{
1370 pub fn of_type(self, spec: TypeSpec<F>) -> Self {
1372 let mut this = self;
1373 this.spec.ty = spec;
1374 this
1375 }
1376
1377 pub fn indexed(self, is_indexed: bool) -> Self {
1379 let mut this = self;
1380 this.spec.indexed = is_indexed;
1381 this
1382 }
1383
1384 pub fn docs<'a, D>(self, docs: D) -> Self
1386 where
1387 D: IntoIterator<Item = &'a str>,
1388 F::String: From<&'a str>,
1389 {
1390 debug_assert!(self.spec.docs.is_empty());
1391 Self {
1392 spec: EventParamSpec {
1393 docs: docs
1394 .into_iter()
1395 .map(|s| trim_extra_whitespace(s).into())
1396 .collect::<Vec<_>>(),
1397 ..self.spec
1398 },
1399 }
1400 }
1401
1402 pub fn done(self) -> EventParamSpec<F> {
1404 self.spec
1405 }
1406}
1407
1408#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1410#[serde(transparent)]
1411#[serde(bound(
1412 serialize = "F::Type: Serialize, F::String: Serialize",
1413 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1414))]
1415#[must_use]
1416pub struct ReturnTypeSpec<F: Form = MetaForm> {
1417 #[serde(rename = "type")]
1418 ret_type: TypeSpec<F>,
1419}
1420
1421impl IntoPortable for ReturnTypeSpec {
1422 type Output = ReturnTypeSpec<PortableForm>;
1423
1424 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1425 ReturnTypeSpec {
1426 ret_type: self.ret_type.into_portable(registry),
1427 }
1428 }
1429}
1430
1431impl<F> ReturnTypeSpec<F>
1432where
1433 F: Form,
1434 TypeSpec<F>: Default,
1435{
1436 pub fn new<T>(ty: T) -> Self
1445 where
1446 T: Into<TypeSpec<F>>,
1447 {
1448 Self {
1449 ret_type: ty.into(),
1450 }
1451 }
1452
1453 pub fn ret_type(&self) -> &TypeSpec<F> {
1455 &self.ret_type
1456 }
1457}
1458
1459#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1461#[serde(bound(
1462 serialize = "F::Type: Serialize, F::String: Serialize",
1463 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1464))]
1465pub struct MessageParamSpec<F: Form = MetaForm> {
1466 label: F::String,
1468 #[serde(rename = "type")]
1470 ty: TypeSpec<F>,
1471}
1472
1473impl IntoPortable for MessageParamSpec {
1474 type Output = MessageParamSpec<PortableForm>;
1475
1476 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1477 MessageParamSpec {
1478 label: self.label.to_string(),
1479 ty: self.ty.into_portable(registry),
1480 }
1481 }
1482}
1483
1484impl<F> MessageParamSpec<F>
1485where
1486 F: Form,
1487 TypeSpec<F>: Default,
1488{
1489 pub fn new(label: F::String) -> MessageParamSpecBuilder<F> {
1491 MessageParamSpecBuilder {
1492 spec: Self {
1493 label,
1494 ty: TypeSpec::default(),
1496 },
1497 }
1498 }
1499
1500 pub fn label(&self) -> &F::String {
1502 &self.label
1503 }
1504
1505 pub fn ty(&self) -> &TypeSpec<F> {
1507 &self.ty
1508 }
1509}
1510
1511#[must_use]
1513pub struct MessageParamSpecBuilder<F: Form> {
1514 spec: MessageParamSpec<F>,
1516}
1517
1518impl<F> MessageParamSpecBuilder<F>
1519where
1520 F: Form,
1521{
1522 pub fn of_type(self, ty: TypeSpec<F>) -> Self {
1524 let mut this = self;
1525 this.spec.ty = ty;
1526 this
1527 }
1528
1529 pub fn done(self) -> MessageParamSpec<F> {
1531 self.spec
1532 }
1533}
1534
1535#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1537#[serde(bound(
1538 serialize = "F::Type: Serialize, F::String: Serialize",
1539 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1540))]
1541#[serde(rename_all = "camelCase")]
1542pub struct EnvironmentSpec<F: Form = MetaForm>
1543where
1544 TypeSpec<F>: Default,
1545{
1546 account_id: TypeSpec<F>,
1547 balance: TypeSpec<F>,
1548 hash: TypeSpec<F>,
1549 timestamp: TypeSpec<F>,
1550 block_number: TypeSpec<F>,
1551 native_to_eth_ratio: u32,
1552 static_buffer_size: usize,
1553}
1554
1555impl<F> Default for EnvironmentSpec<F>
1556where
1557 F: Form,
1558 TypeSpec<F>: Default,
1559{
1560 fn default() -> Self {
1561 Self {
1562 account_id: Default::default(),
1563 balance: Default::default(),
1564 hash: Default::default(),
1565 timestamp: Default::default(),
1566 block_number: Default::default(),
1567 native_to_eth_ratio: Default::default(),
1568 static_buffer_size: Default::default(),
1569 }
1570 }
1571}
1572
1573impl IntoPortable for EnvironmentSpec {
1574 type Output = EnvironmentSpec<PortableForm>;
1575
1576 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1577 EnvironmentSpec {
1578 account_id: self.account_id.into_portable(registry),
1579 balance: self.balance.into_portable(registry),
1580 hash: self.hash.into_portable(registry),
1581 timestamp: self.timestamp.into_portable(registry),
1582 block_number: self.block_number.into_portable(registry),
1583 native_to_eth_ratio: self.native_to_eth_ratio,
1584 static_buffer_size: self.static_buffer_size,
1585 }
1586 }
1587}
1588
1589impl<F> EnvironmentSpec<F>
1590where
1591 F: Form,
1592 TypeSpec<F>: Default,
1593{
1594 pub fn account_id(&self) -> &TypeSpec<F> {
1596 &self.account_id
1597 }
1598 pub fn balance(&self) -> &TypeSpec<F> {
1600 &self.balance
1601 }
1602 pub fn hash(&self) -> &TypeSpec<F> {
1604 &self.hash
1605 }
1606 pub fn timestamp(&self) -> &TypeSpec<F> {
1608 &self.timestamp
1609 }
1610 pub fn block_number(&self) -> &TypeSpec<F> {
1612 &self.block_number
1613 }
1614 pub fn native_to_eth_ratio(&self) -> u32 {
1616 self.native_to_eth_ratio
1617 }
1618}
1619
1620#[allow(clippy::type_complexity)]
1621impl<F> EnvironmentSpec<F>
1622where
1623 F: Form,
1624 TypeSpec<F>: Default,
1625 EnvironmentSpec<F>: Default,
1626{
1627 pub fn new() -> EnvironmentSpecBuilder<
1628 F,
1629 Missing<state::AccountId>,
1630 Missing<state::Balance>,
1631 Missing<state::Hash>,
1632 Missing<state::Timestamp>,
1633 Missing<state::BlockNumber>,
1634 Missing<state::NativeToEthRatio>,
1635 Missing<state::BufferSize>,
1636 > {
1637 EnvironmentSpecBuilder {
1638 spec: Default::default(),
1639 marker: PhantomData,
1640 }
1641 }
1642}
1643
1644#[allow(clippy::type_complexity)]
1646#[must_use]
1647pub struct EnvironmentSpecBuilder<F, A, B, H, T, BN, NTER, BS>
1648where
1649 F: Form,
1650 TypeSpec<F>: Default,
1651 EnvironmentSpec<F>: Default,
1652{
1653 spec: EnvironmentSpec<F>,
1654 marker: PhantomData<fn() -> (A, B, H, T, BN, NTER, BS)>,
1655}
1656
1657impl<F, B, H, T, BN, NTER, BS>
1658 EnvironmentSpecBuilder<F, Missing<state::AccountId>, B, H, T, BN, NTER, BS>
1659where
1660 F: Form,
1661 TypeSpec<F>: Default,
1662 EnvironmentSpec<F>: Default,
1663{
1664 pub fn account_id(
1666 self,
1667 account_id: TypeSpec<F>,
1668 ) -> EnvironmentSpecBuilder<F, state::AccountId, B, H, T, BN, NTER, BS> {
1669 EnvironmentSpecBuilder {
1670 spec: EnvironmentSpec {
1671 account_id,
1672 ..self.spec
1673 },
1674 marker: PhantomData,
1675 }
1676 }
1677}
1678
1679impl<F, A, H, T, BN, NTER, BS>
1680 EnvironmentSpecBuilder<F, A, Missing<state::Balance>, H, T, BN, NTER, BS>
1681where
1682 F: Form,
1683 TypeSpec<F>: Default,
1684 EnvironmentSpec<F>: Default,
1685{
1686 pub fn balance(
1688 self,
1689 balance: TypeSpec<F>,
1690 ) -> EnvironmentSpecBuilder<F, A, state::Balance, H, T, BN, NTER, BS> {
1691 EnvironmentSpecBuilder {
1692 spec: EnvironmentSpec {
1693 balance,
1694 ..self.spec
1695 },
1696 marker: PhantomData,
1697 }
1698 }
1699}
1700
1701impl<F, A, B, T, BN, NTER, BS>
1702 EnvironmentSpecBuilder<F, A, B, Missing<state::Hash>, T, BN, NTER, BS>
1703where
1704 F: Form,
1705 TypeSpec<F>: Default,
1706 EnvironmentSpec<F>: Default,
1707{
1708 pub fn hash(
1710 self,
1711 hash: TypeSpec<F>,
1712 ) -> EnvironmentSpecBuilder<F, A, B, state::Hash, T, BN, NTER, BS> {
1713 EnvironmentSpecBuilder {
1714 spec: EnvironmentSpec { hash, ..self.spec },
1715 marker: PhantomData,
1716 }
1717 }
1718}
1719
1720impl<F, A, B, H, BN, NTER, BS>
1721 EnvironmentSpecBuilder<F, A, B, H, Missing<state::Timestamp>, BN, NTER, BS>
1722where
1723 F: Form,
1724 TypeSpec<F>: Default,
1725 EnvironmentSpec<F>: Default,
1726{
1727 pub fn timestamp(
1729 self,
1730 timestamp: TypeSpec<F>,
1731 ) -> EnvironmentSpecBuilder<F, A, B, H, state::Timestamp, BN, NTER, BS> {
1732 EnvironmentSpecBuilder {
1733 spec: EnvironmentSpec {
1734 timestamp,
1735 ..self.spec
1736 },
1737 marker: PhantomData,
1738 }
1739 }
1740}
1741
1742impl<F, A, B, H, T, NTER, BS>
1743 EnvironmentSpecBuilder<F, A, B, H, T, Missing<state::BlockNumber>, NTER, BS>
1744where
1745 F: Form,
1746 TypeSpec<F>: Default,
1747 EnvironmentSpec<F>: Default,
1748{
1749 pub fn block_number(
1751 self,
1752 block_number: TypeSpec<F>,
1753 ) -> EnvironmentSpecBuilder<F, A, B, H, T, state::BlockNumber, NTER, BS> {
1754 EnvironmentSpecBuilder {
1755 spec: EnvironmentSpec {
1756 block_number,
1757 ..self.spec
1758 },
1759 marker: PhantomData,
1760 }
1761 }
1762}
1763
1764impl<F, A, B, H, T, BN, BS>
1765 EnvironmentSpecBuilder<F, A, B, H, T, BN, Missing<state::NativeToEthRatio>, BS>
1766where
1767 F: Form,
1768 TypeSpec<F>: Default,
1769 EnvironmentSpec<F>: Default,
1770{
1771 pub fn native_to_eth_ratio(
1773 self,
1774 native_to_eth_ratio: u32,
1775 ) -> EnvironmentSpecBuilder<F, A, B, H, T, BN, state::NativeToEthRatio, BS> {
1776 EnvironmentSpecBuilder {
1777 spec: EnvironmentSpec {
1778 native_to_eth_ratio,
1779 ..self.spec
1780 },
1781 marker: PhantomData,
1782 }
1783 }
1784}
1785
1786impl<F, A, B, H, T, BN, NTER>
1787 EnvironmentSpecBuilder<F, A, B, H, T, BN, NTER, Missing<state::BufferSize>>
1788where
1789 F: Form,
1790 TypeSpec<F>: Default,
1791 EnvironmentSpec<F>: Default,
1792{
1793 pub fn static_buffer_size(
1795 self,
1796 static_buffer_size: usize,
1797 ) -> EnvironmentSpecBuilder<F, A, B, H, T, BN, NTER, state::BufferSize> {
1798 EnvironmentSpecBuilder {
1799 spec: EnvironmentSpec {
1800 static_buffer_size,
1801 ..self.spec
1802 },
1803 marker: PhantomData,
1804 }
1805 }
1806}
1807
1808impl<F>
1809 EnvironmentSpecBuilder<
1810 F,
1811 state::AccountId,
1812 state::Balance,
1813 state::Hash,
1814 state::Timestamp,
1815 state::BlockNumber,
1816 state::NativeToEthRatio,
1817 state::BufferSize,
1818 >
1819where
1820 F: Form,
1821 TypeSpec<F>: Default,
1822 EnvironmentSpec<F>: Default,
1823{
1824 pub fn done(self) -> EnvironmentSpec<F> {
1826 self.spec
1827 }
1828}