1use crate::{
5 indent::{IndentConfig, IndentedWriter},
6 CodeGeneratorConfig,
7};
8use heck::SnakeCase;
9use phf::phf_set;
10use serde_reflection::{ContainerFormat, Format, Named, Registry, VariantFormat};
11use std::{
12 collections::{BTreeMap, HashSet},
13 io::{Result, Write},
14 path::PathBuf,
15};
16
17pub struct CodeGenerator<'a> {
19 config: &'a CodeGeneratorConfig,
21}
22
23struct SolEmitter<'a, T> {
25 out: IndentedWriter<T>,
27 generator: &'a CodeGenerator<'a>,
29}
30
31fn get_data_location(need_memory: bool) -> String {
32 match need_memory {
33 true => " memory".to_string(),
34 false => "".to_string(),
35 }
36}
37
38fn output_generic_bcs_deserialize<T: std::io::Write>(
39 out: &mut IndentedWriter<T>,
40 key_name: &str,
41 code_name: &str,
42 need_memory: bool,
43) -> Result<()> {
44 let data_location = get_data_location(need_memory);
45 writeln!(
46 out,
47 r#"
48function bcs_deserialize_{key_name}(bytes memory input)
49 internal
50 pure
51 returns ({code_name}{data_location})
52{{
53 uint256 new_pos;
54 {code_name}{data_location} value;
55 (new_pos, value) = bcs_deserialize_offset_{key_name}(0, input);
56 require(new_pos == input.length, "incomplete deserialization");
57 return value;
58}}"#
59 )?;
60 Ok(())
61}
62
63static KEYWORDS: phf::Set<&str> = phf_set! {
64 "abstract", "after", "alias", "anonymous",
65 "as", "assembly", "break", "catch", "constant",
66 "continue", "constructor", "contract", "delete",
67 "do", "else", "emit", "enum", "error", "event",
68 "external", "fallback", "for", "function", "if",
69 "immutable", "import", "indexed", "interface",
70 "internal", "is", "library", "mapping", "memory",
71 "modifier", "new", "override", "payable", "pragma",
72 "private", "public", "pure", "receive", "return",
73 "returns", "revert", "storage", "struct", "throw",
74 "try", "type", "unchecked", "using", "virtual",
75 "view", "while", "addmod", "blockhash", "ecrecover",
76 "keccak256", "mulmod", "sha256", "ripemd160",
77 "block", "msg", "tx", "balance", "transfer", "send",
78 "call", "delegatecall", "staticcall", "this",
79 "super", "gwei", "finney", "szabo", "ether",
80 "seconds", "minutes", "hours", "days", "weeks",
81 "years", "wei", "hex", "address", "bool", "bytes",
82 "string", "int", "int8", "int16", "int32", "int64",
83 "int128", "int256", "uint", "uint8", "uint16",
84 "uint32", "uint64", "uint128", "uint256",
85 "bytes1", "bytes2", "bytes3", "bytes4", "bytes5",
86 "bytes6", "bytes7", "bytes8", "bytes9", "bytes10",
87 "bytes11", "bytes12", "bytes13", "bytes14", "bytes15",
88 "bytes16", "bytes17", "bytes18", "bytes19", "bytes20",
89 "bytes21", "bytes22", "bytes23", "bytes24", "bytes25",
90 "bytes26", "bytes27", "bytes28", "bytes29", "bytes30",
91 "bytes31", "bytes32"
92};
93
94fn safe_variable(s: &str) -> String {
95 if KEYWORDS.contains(s) {
96 s.to_owned() + "_"
97 } else {
98 s.to_string()
99 }
100}
101
102#[derive(Clone, Debug, PartialEq)]
103enum Primitive {
104 Unit,
105 Bool,
106 I8,
107 I16,
108 I32,
109 I64,
110 I128,
111 U8,
112 U16,
113 U32,
114 U64,
115 U128,
116 Char,
117 Str,
118 Bytes,
119}
120
121impl Primitive {
122 pub fn name(&self) -> String {
123 use Primitive::*;
124 match self {
125 Unit => "empty_struct".into(),
126 Bool => "bool".into(),
127 I8 => "int8".into(),
128 I16 => "int16".into(),
129 I32 => "int32".into(),
130 I64 => "int64".into(),
131 I128 => "int128".into(),
132 U8 => "uint8".into(),
133 U16 => "uint16".into(),
134 U32 => "uint32".into(),
135 U64 => "uint64".into(),
136 U128 => "uint128".into(),
137 Char => "bytes1".into(),
138 Str => "string".into(),
139 Bytes => "bytes".into(),
140 }
141 }
142
143 pub fn need_memory(&self) -> bool {
144 matches!(self, Primitive::Unit | Primitive::Bytes | Primitive::Str)
145 }
146
147 pub fn output<T: std::io::Write>(&self, out: &mut IndentedWriter<T>) -> Result<()> {
148 use Primitive::*;
149 match self {
150 Unit => writeln!(
151 out,
152 r#"
153struct empty_struct {{
154 int8 val;
155}}
156
157function bcs_serialize_empty_struct(empty_struct memory input)
158 internal
159 pure
160 returns (bytes memory)
161{{
162 bytes memory result;
163 return result;
164}}
165
166function bcs_deserialize_offset_empty_struct(uint256 pos, bytes memory input)
167 internal
168 pure
169 returns (uint256, empty_struct memory)
170{{
171 int8 val = 0;
172 return (pos, empty_struct(val));
173}}"#
174 )?,
175 Bool => {
176 writeln!(
177 out,
178 r#"
179function bcs_serialize_bool(bool input)
180 internal
181 pure
182 returns (bytes memory)
183{{
184 return abi.encodePacked(input);
185}}
186
187function bcs_deserialize_offset_bool(uint256 pos, bytes memory input)
188 internal
189 pure
190 returns (uint256, bool)
191{{
192 uint8 val = uint8(input[pos]);
193 bool result = false;
194 if (val == 1) {{
195 result = true;
196 }} else {{
197 require(val == 0);
198 }}
199 return (pos + 1, result);
200}}"#
201 )?;
202 }
203 I8 => {
204 writeln!(
205 out,
206 r#"
207function bcs_serialize_int8(int8 input)
208 internal
209 pure
210 returns (bytes memory)
211{{
212 return abi.encodePacked(input);
213}}
214
215function bcs_deserialize_offset_int8(uint256 pos, bytes memory input)
216 internal
217 pure
218 returns (uint256, int8)
219{{
220 int16 val = int16(uint16(uint8(input[pos])));
221 if (val < 128) {{
222 return (pos + 1, int8(val));
223 }} else {{
224 return (pos + 1, int8(val - 256));
225 }}
226}}"#
227 )?;
228 }
229 I16 => writeln!(
230 out,
231 r#"
232function bcs_serialize_int16(int16 input)
233 internal
234 pure
235 returns (bytes memory)
236{{
237 bytes memory result = new bytes(2);
238 uint16 uinput;
239 if (input >= 0) {{
240 uinput = uint16(input);
241 }} else {{
242 int32 input_32 = int32(input) + 65536;
243 uinput = uint16(uint32(input_32));
244 }}
245 return bcs_serialize_uint16(uinput);
246}}
247
248function bcs_deserialize_offset_int16(uint256 pos, bytes memory input)
249 internal
250 pure
251 returns (uint256, int16)
252{{
253 uint256 new_pos;
254 uint16 uresult;
255 (new_pos, uresult) = bcs_deserialize_offset_uint16(pos, input);
256 int16 result;
257 if (uresult < 32768) {{
258 result = int16(uresult);
259 return (new_pos, result);
260 }} else {{
261 int32 result_32 = int32(uint32(uresult)) - 65536;
262 result = int16(result_32);
263 }}
264 return (new_pos, result);
265}}"#
266 )?,
267 I32 => {
268 writeln!(
269 out,
270 r#"
271function bcs_serialize_int32(int32 input)
272 internal
273 pure
274 returns (bytes memory)
275{{
276 bytes memory result = new bytes(4);
277 uint32 uinput;
278 if (input >= 0) {{
279 uinput = uint32(input);
280 }} else {{
281 int64 input_64 = int64(input) + 4294967296;
282 uinput = uint32(uint64(input_64));
283 }}
284 return bcs_serialize_uint32(uinput);
285}}
286
287function bcs_deserialize_offset_int32(uint256 pos, bytes memory input)
288 internal
289 pure
290 returns (uint256, int32)
291{{
292 uint256 new_pos;
293 uint32 uresult;
294 (new_pos, uresult) = bcs_deserialize_offset_uint32(pos, input);
295 int32 result;
296 if (uresult < 2147483648) {{
297 result = int32(uresult);
298 return (new_pos, result);
299 }} else {{
300 int64 result_64 = int64(uint64(uresult)) - 4294967296;
301 result = int32(result_64);
302 }}
303 return (new_pos, result);
304}}"#
305 )?;
306 }
307 I64 => {
308 writeln!(
309 out,
310 r#"
311function bcs_serialize_int64(int64 input)
312 internal
313 pure
314 returns (bytes memory)
315{{
316 bytes memory result = new bytes(8);
317 uint64 uinput;
318 if (input >= 0) {{
319 uinput = uint64(input);
320 }} else {{
321 int128 input_128 = int128(input) + 18446744073709551616;
322 uinput = uint64(uint128(input_128));
323 }}
324 return bcs_serialize_uint64(uinput);
325}}
326
327function bcs_deserialize_offset_int64(uint256 pos, bytes memory input)
328 internal
329 pure
330 returns (uint256, int64)
331{{
332 uint256 new_pos;
333 uint64 uresult;
334 (new_pos, uresult) = bcs_deserialize_offset_uint64(pos, input);
335 int64 result;
336 if (uresult < 9223372036854775808) {{
337 result = int64(uresult);
338 return (new_pos, result);
339 }} else {{
340 int128 result_128 = int128(uint128(uresult)) - 18446744073709551616;
341 result = int64(result_128);
342 }}
343 return (new_pos, result);
344}}"#
345 )?;
346 }
347 I128 => {
348 writeln!(
349 out,
350 r#"
351function bcs_serialize_int128(int128 input)
352 internal
353 pure
354 returns (bytes memory)
355{{
356 bytes memory result = new bytes(16);
357 uint128 uinput;
358 if (input >= 0) {{
359 uinput = uint128(input);
360 }} else {{
361 int256 input_256 = int256(input) + 340282366920938463463374607431768211456;
362 uinput = uint128(uint256(input_256));
363 }}
364 return bcs_serialize_uint128(uinput);
365}}
366
367function bcs_deserialize_offset_int128(uint256 pos, bytes memory input)
368 internal
369 pure
370 returns (uint256, int128)
371{{
372 uint256 new_pos;
373 uint128 uresult;
374 (new_pos, uresult) = bcs_deserialize_offset_uint128(pos, input);
375 int128 result;
376 if (uresult < 170141183460469231731687303715884105728) {{
377 result = int128(uresult);
378 return (new_pos, result);
379 }} else {{
380 int256 result_256 = int256(uint256(uresult)) - 340282366920938463463374607431768211456;
381 result = int128(result_256);
382 }}
383 return (new_pos, result);
384}}"#
385 )?;
386 }
387 U8 => {
388 writeln!(
389 out,
390 r#"
391function bcs_serialize_uint8(uint8 input)
392 internal
393 pure
394 returns (bytes memory)
395{{
396 return abi.encodePacked(input);
397}}
398
399function bcs_deserialize_offset_uint8(uint256 pos, bytes memory input)
400 internal
401 pure
402 returns (uint256, uint8)
403{{
404 uint8 value = uint8(input[pos]);
405 return (pos + 1, value);
406}}"#
407 )?;
408 }
409 U16 => {
410 writeln!(
411 out,
412 r#"
413function bcs_serialize_uint16(uint16 input)
414 internal
415 pure
416 returns (bytes memory)
417{{
418 bytes memory result = new bytes(2);
419 uint16 value = input;
420 result[0] = bytes1(uint8(value));
421 value = value >> 8;
422 result[1] = bytes1(uint8(value));
423 return result;
424}}
425
426function bcs_deserialize_offset_uint16(uint256 pos, bytes memory input)
427 internal
428 pure
429 returns (uint256, uint16)
430{{
431 uint16 value = uint8(input[pos+1]);
432 value = value << 8;
433 value += uint8(input[pos]);
434 return (pos + 2, value);
435}}"#
436 )?;
437 }
438 U32 => {
439 writeln!(
440 out,
441 r#"
442function bcs_serialize_uint32(uint32 input)
443 internal
444 pure
445 returns (bytes memory)
446{{
447 bytes memory result = new bytes(4);
448 uint32 value = input;
449 result[0] = bytes1(uint8(value));
450 for (uint i=1; i<4; i++) {{
451 value = value >> 8;
452 result[i] = bytes1(uint8(value));
453 }}
454 return result;
455}}
456
457function bcs_deserialize_offset_uint32(uint256 pos, bytes memory input)
458 internal
459 pure
460 returns (uint256, uint32)
461{{
462 uint32 value = uint8(input[pos + 3]);
463 for (uint256 i=0; i<3; i++) {{
464 value = value << 8;
465 value += uint8(input[pos + 2 - i]);
466 }}
467 return (pos + 4, value);
468}}"#
469 )?;
470 }
471 U64 => {
472 writeln!(
473 out,
474 r#"
475function bcs_serialize_uint64(uint64 input)
476 internal
477 pure
478 returns (bytes memory)
479{{
480 bytes memory result = new bytes(8);
481 uint64 value = input;
482 result[0] = bytes1(uint8(value));
483 for (uint i=1; i<8; i++) {{
484 value = value >> 8;
485 result[i] = bytes1(uint8(value));
486 }}
487 return result;
488}}
489
490function bcs_deserialize_offset_uint64(uint256 pos, bytes memory input)
491 internal
492 pure
493 returns (uint256, uint64)
494{{
495 uint64 value = uint8(input[pos + 7]);
496 for (uint256 i=0; i<7; i++) {{
497 value = value << 8;
498 value += uint8(input[pos + 6 - i]);
499 }}
500 return (pos + 8, value);
501}}"#
502 )?;
503 }
504 U128 => {
505 writeln!(
506 out,
507 r#"
508function bcs_serialize_uint128(uint128 input)
509 internal
510 pure
511 returns (bytes memory)
512{{
513 bytes memory result = new bytes(16);
514 uint128 value = input;
515 result[0] = bytes1(uint8(value));
516 for (uint i=1; i<16; i++) {{
517 value = value >> 8;
518 result[i] = bytes1(uint8(value));
519 }}
520 return result;
521}}
522
523function bcs_deserialize_offset_uint128(uint256 pos, bytes memory input)
524 internal
525 pure
526 returns (uint256, uint128)
527{{
528 uint128 value = uint8(input[pos + 15]);
529 for (uint256 i=0; i<15; i++) {{
530 value = value << 8;
531 value += uint8(input[pos + 14 - i]);
532 }}
533 return (pos + 16, value);
534}}"#
535 )?;
536 }
537 Char => {
538 writeln!(
539 out,
540 r#"
541function bcs_serialize_bytes1(bytes1 input)
542 internal
543 pure
544 returns (bytes memory)
545{{
546 return abi.encodePacked(input);
547}}
548
549function bcs_deserialize_offset_bytes1(uint256 pos, bytes memory input)
550 internal
551 pure
552 returns (uint256, bytes1)
553{{
554 bytes1 result = bytes1(input[pos]);
555 return (pos + 1, result);
556}}"#
557 )?;
558 }
559 Str => {
560 writeln!(
561 out,
562 r#"
563function bcs_serialize_string(string memory input)
564 internal
565 pure
566 returns (bytes memory)
567{{
568 bytes memory input_bytes = bytes(input);
569 uint256 number_bytes = input_bytes.length;
570 uint256 number_char = 0;
571 uint256 pos = 0;
572 while (true) {{
573 if (uint8(input_bytes[pos]) < 128) {{
574 number_char += 1;
575 }}
576 pos += 1;
577 if (pos == number_bytes) {{
578 break;
579 }}
580 }}
581 bytes memory result_len = bcs_serialize_len(number_char);
582 return abi.encodePacked(result_len, input);
583}}
584
585function bcs_deserialize_offset_string(uint256 pos, bytes memory input)
586 internal
587 pure
588 returns (uint256, string memory)
589{{
590 uint256 len;
591 uint256 new_pos;
592 (new_pos, len) = bcs_deserialize_offset_len(pos, input);
593 uint256 shift = 0;
594 for (uint256 i=0; i<len; i++) {{
595 while (true) {{
596 bytes1 val = input[new_pos + shift];
597 shift += 1;
598 if (uint8(val) < 128) {{
599 break;
600 }}
601 }}
602 }}
603 bytes memory result_bytes = new bytes(shift);
604 for (uint256 i=0; i<shift; i++) {{
605 result_bytes[i] = input[new_pos + i];
606 }}
607 string memory result = string(result_bytes);
608 return (new_pos + shift, result);
609}}
610"#
611 )?;
612 }
613 Bytes => {
614 writeln!(
615 out,
616 r#"
617function bcs_serialize_bytes(bytes memory input)
618 internal
619 pure
620 returns (bytes memory)
621{{
622 uint256 len = input.length;
623 bytes memory result = bcs_serialize_len(len);
624 return abi.encodePacked(result, input);
625}}
626
627function bcs_deserialize_offset_bytes(uint256 pos, bytes memory input)
628 internal
629 pure
630 returns (uint256, bytes memory)
631{{
632 uint256 len;
633 uint256 new_pos;
634 (new_pos, len) = bcs_deserialize_offset_len(pos, input);
635 bytes memory result = new bytes(len);
636 for (uint256 u=0; u<len; u++) {{
637 result[u] = input[new_pos + u];
638 }}
639 return (new_pos + len, result);
640}}"#
641 )?;
642 }
643 }
644 Ok(())
645 }
646}
647
648#[derive(Clone, Debug, PartialEq)]
649enum SolFormat {
650 Primitive(Primitive),
652 TypeName(String),
654 Seq(Box<SolFormat>),
656 SimpleEnum { name: String, names: Vec<String> },
658 Struct {
660 name: String,
661 formats: Vec<Named<SolFormat>>,
662 },
663 Option(Box<SolFormat>),
665 TupleArray { format: Box<SolFormat>, size: usize },
667 Enum {
669 name: String,
670 formats: Vec<Named<Option<SolFormat>>>,
671 },
672 BytesN { size: usize },
674 OptionBool,
676}
677
678impl SolFormat {
679 pub fn code_name(&self) -> String {
680 use SolFormat::*;
681 if let Seq(format) = self {
682 return format!("{}[]", format.code_name());
683 }
684 self.key_name()
685 }
686
687 pub fn key_name(&self) -> String {
688 use SolFormat::*;
689 match self {
690 Primitive(primitive) => primitive.name(),
691 TypeName(name) => name.to_string(),
692 Option(format) => format!("opt_{}", format.key_name()),
693 Seq(format) => format!("seq_{}", format.key_name()),
694 TupleArray { format, size } => format!("tuplearray{}_{}", size, format.key_name()),
695 Struct { name, formats: _ } => name.to_string(),
696 SimpleEnum { name, names: _ } => name.to_string(),
697 Enum { name, formats: _ } => name.to_string(),
698 BytesN { size } => format!("bytes{size}"),
699 OptionBool => "OptionBool".to_string(),
700 }
701 }
702
703 pub fn output<T: std::io::Write>(
704 &self,
705 out: &mut IndentedWriter<T>,
706 sol_registry: &SolRegistry,
707 ) -> Result<()> {
708 use SolFormat::*;
709 match self {
710 Primitive(primitive) => {
711 primitive.output(out)?;
712 let full_name = primitive.name();
713 let need_memory = primitive.need_memory();
714 output_generic_bcs_deserialize(out, &full_name, &full_name, need_memory)?;
715 }
716 TypeName(_) => {
717 }
719 Option(format) => {
720 let key_name = format.key_name();
721 let code_name = format.code_name();
722 let full_name = format!("opt_{}", key_name);
723 let data_location = sol_registry.data_location(format);
724 writeln!(
725 out,
726 r#"
727struct {full_name} {{
728 bool has_value;
729 {code_name} value;
730}}
731
732function bcs_serialize_{full_name}({full_name} memory input)
733 internal
734 pure
735 returns (bytes memory)
736{{
737 if (input.has_value) {{
738 return abi.encodePacked(uint8(1), bcs_serialize_{key_name}(input.value));
739 }} else {{
740 return abi.encodePacked(uint8(0));
741 }}
742}}
743
744function bcs_deserialize_offset_{full_name}(uint256 pos, bytes memory input)
745 internal
746 pure
747 returns (uint256, {full_name} memory)
748{{
749 uint256 new_pos;
750 bool has_value;
751 (new_pos, has_value) = bcs_deserialize_offset_bool(pos, input);
752 {code_name}{data_location} value;
753 if (has_value) {{
754 (new_pos, value) = bcs_deserialize_offset_{key_name}(new_pos, input);
755 }}
756 return (new_pos, {full_name}(has_value, value));
757}}"#
758 )?;
759 output_generic_bcs_deserialize(out, &full_name, &full_name, true)?;
760 }
761 Seq(format) => {
762 let inner_key_name = format.key_name();
763 let inner_code_name = format.code_name();
764 let code_name = format!("{}[]", format.code_name());
765 let key_name = format!("seq_{}", format.key_name());
766 let data_location = sol_registry.data_location(format);
767 writeln!(
768 out,
769 r#"
770function bcs_serialize_{key_name}({code_name} memory input)
771 internal
772 pure
773 returns (bytes memory)
774{{
775 uint256 len = input.length;
776 bytes memory result = bcs_serialize_len(len);
777 for (uint256 i=0; i<len; i++) {{
778 result = abi.encodePacked(result, bcs_serialize_{inner_key_name}(input[i]));
779 }}
780 return result;
781}}
782
783function bcs_deserialize_offset_{key_name}(uint256 pos, bytes memory input)
784 internal
785 pure
786 returns (uint256, {code_name} memory)
787{{
788 uint256 len;
789 uint256 new_pos;
790 (new_pos, len) = bcs_deserialize_offset_len(pos, input);
791 {inner_code_name}[] memory result;
792 result = new {inner_code_name}[](len);
793 {inner_code_name}{data_location} value;
794 for (uint256 i=0; i<len; i++) {{
795 (new_pos, value) = bcs_deserialize_offset_{inner_key_name}(new_pos, input);
796 result[i] = value;
797 }}
798 return (new_pos, result);
799}}"#
800 )?;
801 output_generic_bcs_deserialize(out, &key_name, &code_name, true)?;
802 }
803 TupleArray { format, size } => {
804 let inner_key_name = format.key_name();
805 let inner_code_name = format.code_name();
806 let struct_name = format!("tuplearray{}_{}", size, inner_key_name);
807 writeln!(
808 out,
809 r#"
810struct {struct_name} {{
811 {inner_code_name}[] values;
812}}
813
814function bcs_serialize_{struct_name}({struct_name} memory input)
815 internal
816 pure
817 returns (bytes memory)
818{{
819 bytes memory result;
820 for (uint i=0; i<{size}; i++) {{
821 result = abi.encodePacked(result, bcs_serialize_{inner_key_name}(input.values[i]));
822 }}
823 return result;
824}}
825
826function bcs_deserialize_offset_{struct_name}(uint256 pos, bytes memory input)
827 internal
828 pure
829 returns (uint256, {struct_name} memory)
830{{
831 uint256 new_pos = pos;
832 {inner_code_name} value;
833 {inner_code_name}[] memory values;
834 values = new {inner_code_name}[]({size});
835 for (uint i=0; i<{size}; i++) {{
836 (new_pos, value) = bcs_deserialize_offset_{inner_key_name}(new_pos, input);
837 values[i] = value;
838 }}
839 return (new_pos, {struct_name}(values));
840}}"#
841 )?;
842 output_generic_bcs_deserialize(out, &struct_name, &struct_name, true)?;
843 }
844 Struct { name, formats } => {
845 writeln!(out)?;
846 writeln!(out, "struct {name} {{")?;
847 for named_format in formats {
848 writeln!(
849 out,
850 " {} {};",
851 named_format.value.code_name(),
852 safe_variable(&named_format.name)
853 )?;
854 }
855 writeln!(
856 out,
857 r#"}}
858
859function bcs_serialize_{name}({name} memory input)
860 internal
861 pure
862 returns (bytes memory)
863{{"#
864 )?;
865 for (index, named_format) in formats.iter().enumerate() {
866 let key_name = named_format.value.key_name();
867 let safe_name = safe_variable(&named_format.name);
868 let block = format!("bcs_serialize_{key_name}(input.{safe_name})");
869 let block = if formats.len() > 1 {
870 if index == 0 {
871 format!("bytes memory result = {block}")
872 } else if index < formats.len() - 1 {
873 format!("result = abi.encodePacked(result, {block})")
874 } else {
875 format!("return abi.encodePacked(result, {block})")
876 }
877 } else {
878 format!("return {block}")
879 };
880 writeln!(out, " {block};")?;
881 }
882 writeln!(
883 out,
884 r#"}}
885
886function bcs_deserialize_offset_{name}(uint256 pos, bytes memory input)
887 internal
888 pure
889 returns (uint256, {name} memory)
890{{
891 uint256 new_pos;"#
892 )?;
893 for (index, named_format) in formats.iter().enumerate() {
894 let data_location = sol_registry.data_location(&named_format.value);
895 let code_name = named_format.value.code_name();
896 let key_name = named_format.value.key_name();
897 let safe_name = safe_variable(&named_format.name);
898 let start_pos = if index == 0 { "pos" } else { "new_pos" };
899 writeln!(out, " {code_name}{data_location} {safe_name};")?;
900 writeln!(out, " (new_pos, {safe_name}) = bcs_deserialize_offset_{key_name}({start_pos}, input);")?;
901 }
902 writeln!(
903 out,
904 " return (new_pos, {name}({}));",
905 formats
906 .iter()
907 .map(|named_format| safe_variable(&named_format.name))
908 .collect::<Vec<_>>()
909 .join(", ")
910 )?;
911 writeln!(out, "}}")?;
912 output_generic_bcs_deserialize(out, name, name, true)?;
913 }
914 SimpleEnum { name, names } => {
915 let names_join = names.join(", ");
916 let number_names = names.len();
917 writeln!(
918 out,
919 r#"
920enum {name} {{ {names_join} }}
921
922function bcs_serialize_{name}({name} input)
923 internal
924 pure
925 returns (bytes memory)
926{{
927 return abi.encodePacked(input);
928}}
929
930function bcs_deserialize_offset_{name}(uint256 pos, bytes memory input)
931 internal
932 pure
933 returns (uint256, {name})
934{{
935 uint8 choice = uint8(input[pos]);"#
936 )?;
937 for (idx, name_choice) in names.iter().enumerate() {
938 writeln!(
939 out,
940 r#"
941 if (choice == {idx}) {{
942 return (pos + 1, {name}.{name_choice});
943 }}"#
944 )?;
945 }
946 writeln!(
947 out,
948 r#"
949 require(choice < {number_names});
950}}"#
951 )?;
952 output_generic_bcs_deserialize(out, name, name, false)?;
953 }
954 Enum { name, formats } => {
955 let number_names = formats.len();
956 writeln!(
957 out,
958 r#"
959struct {name} {{
960 uint8 choice;"#
961 )?;
962 for (idx, named_format) in formats.iter().enumerate() {
963 let name = named_format.name.clone();
964 writeln!(out, " // choice={idx} corresponds to {name}")?;
965 if let Some(format) = &named_format.value {
966 let code_name = format.code_name();
967 let snake_name = safe_variable(&named_format.name.to_snake_case());
968 writeln!(out, " {code_name} {snake_name};")?;
969 }
970 }
971 writeln!(out, "}}")?;
972 let mut entries = Vec::new();
973 let mut type_vars = Vec::new();
974 for named_format in formats {
975 if let Some(format) = &named_format.value {
976 let data_location = sol_registry.data_location(format);
977 let snake_name = safe_variable(&named_format.name.to_snake_case());
978 let code_name = format.code_name();
979 let type_var = format!("{code_name}{data_location} {snake_name}");
980 type_vars.push(type_var);
981 entries.push(snake_name);
982 } else {
983 type_vars.push(String::new());
984 }
985 }
986 let entries = entries.join(", ");
987 for (choice, named_format_i) in formats.iter().enumerate() {
988 let snake_name = named_format_i.name.to_snake_case();
989 let type_var = &type_vars[choice];
990 writeln!(
991 out,
992 r#"
993function {name}_case_{snake_name}({type_var})
994 internal
995 pure
996 returns ({name} memory)
997{{"#
998 )?;
999 for (i_choice, type_var) in type_vars.iter().enumerate() {
1000 if !type_var.is_empty() && choice != i_choice {
1001 writeln!(out, " {type_var};")?;
1002 }
1003 }
1004 writeln!(out, " return {name}(uint8({choice}), {entries});")?;
1005 writeln!(out, "}}")?;
1006 }
1007 writeln!(
1008 out,
1009 r#"
1010function bcs_serialize_{name}({name} memory input)
1011 internal
1012 pure
1013 returns (bytes memory)
1014{{"#
1015 )?;
1016 for (idx, named_format) in formats.iter().enumerate() {
1017 if let Some(format) = &named_format.value {
1018 let key_name = format.key_name();
1019 let snake_name = safe_variable(&named_format.name.to_snake_case());
1020 writeln!(out, " if (input.choice == {idx}) {{")?;
1021 writeln!(out, " return abi.encodePacked(input.choice, bcs_serialize_{key_name}(input.{snake_name}));")?;
1022 writeln!(out, " }}")?;
1023 }
1024 }
1025 writeln!(
1026 out,
1027 r#" return abi.encodePacked(input.choice);
1028}}
1029
1030function bcs_deserialize_offset_{name}(uint256 pos, bytes memory input)
1031 internal
1032 pure
1033 returns (uint256, {name} memory)
1034{{
1035 uint256 new_pos;
1036 uint8 choice;
1037 (new_pos, choice) = bcs_deserialize_offset_uint8(pos, input);"#
1038 )?;
1039 let mut entries = Vec::new();
1040 for (idx, named_format) in formats.iter().enumerate() {
1041 if let Some(format) = &named_format.value {
1042 let data_location = sol_registry.data_location(format);
1043 let snake_name = safe_variable(&named_format.name.to_snake_case());
1044 let code_name = format.code_name();
1045 let key_name = format.key_name();
1046 writeln!(out, " {code_name}{data_location} {snake_name};")?;
1047 writeln!(out, " if (choice == {idx}) {{")?;
1048 writeln!(out, " (new_pos, {snake_name}) = bcs_deserialize_offset_{key_name}(new_pos, input);")?;
1049 writeln!(out, " }}")?;
1050 entries.push(snake_name);
1051 }
1052 }
1053 writeln!(out, " require(choice < {number_names});")?;
1054 let entries = entries.join(", ");
1055 writeln!(
1056 out,
1057 r#" return (new_pos, {name}(choice, {entries}));
1058}}"#
1059 )?;
1060 output_generic_bcs_deserialize(out, name, name, true)?;
1061 }
1062 BytesN { size } => {
1063 let name = format!("bytes{size}");
1064 writeln!(
1065 out,
1066 r#"
1067function bcs_serialize_{name}({name} input)
1068 internal
1069 pure
1070 returns (bytes memory)
1071{{
1072 return abi.encodePacked(input);
1073}}
1074
1075function bcs_deserialize_offset_{name}(uint256 pos, bytes memory input)
1076 internal
1077 pure
1078 returns (uint256, {name})
1079{{
1080 {name} dest;
1081 assembly {{
1082 dest := mload(add(add(input, 0x20), pos))
1083 }}
1084 return (pos + {size}, dest);
1085}}"#
1086 )?;
1087 }
1088 OptionBool => {
1089 let name = "OptionBool";
1090 writeln!(
1091 out,
1092 r#"
1093enum {name} {{ None, True, False }}
1094
1095function bcs_serialize_{name}({name} input)
1096 internal
1097 pure
1098 returns (bytes memory)
1099{{
1100 if (input == {name}.None) {{
1101 return abi.encodePacked(uint8(0));
1102 }}
1103 if (input == {name}.False) {{
1104 return abi.encodePacked(uint8(1), uint8(0));
1105 }}
1106 return abi.encodePacked(uint8(1), uint8(1));
1107}}
1108
1109function bcs_deserialize_offset_{name}(uint256 pos, bytes memory input)
1110 internal
1111 pure
1112 returns (uint256, {name})
1113{{
1114 uint8 choice = uint8(input[pos]);
1115 if (choice == 0) {{
1116 return (pos + 1, {name}.None);
1117 }} else {{
1118 require(choice == 1);
1119 uint8 value = uint8(input[pos + 1]);
1120 if (value == 0) {{
1121 return (pos + 2, {name}.False);
1122 }} else {{
1123 require(value == 1);
1124 return (pos + 2, {name}.True);
1125 }}
1126 }}
1127}}"#
1128 )?;
1129 output_generic_bcs_deserialize(out, name, name, false)?;
1130 }
1131 }
1132 Ok(())
1133 }
1134
1135 fn get_dependency(&self) -> Vec<String> {
1136 use SolFormat::*;
1137 match self {
1138 Primitive(_) => vec![],
1139 TypeName(name) => vec![name.to_string()],
1140 Seq(format) => vec![format.key_name()],
1141 SimpleEnum { name: _, names: _ } => vec![],
1142 Struct { name: _, formats } => formats
1143 .iter()
1144 .map(|format| format.value.key_name())
1145 .collect(),
1146 Option(format) => vec![format.key_name()],
1147 TupleArray { format, size: _ } => vec![format.key_name()],
1148 Enum { name: _, formats } => formats
1149 .iter()
1150 .flat_map(|format| match &format.value {
1151 None => vec![],
1152 Some(format) => vec![format.key_name()],
1153 })
1154 .collect(),
1155 BytesN { size: _ } => vec![],
1156 OptionBool => vec![],
1157 }
1158 }
1159}
1160
1161#[derive(Default)]
1162struct SolRegistry {
1163 names: BTreeMap<String, SolFormat>,
1164}
1165
1166impl SolRegistry {
1167 fn insert(&mut self, sol_format: SolFormat) {
1168 let key_name = sol_format.key_name();
1169 match sol_format {
1171 SolFormat::Primitive(Primitive::I8) => {
1172 self.names.insert(key_name, sol_format);
1173 self.names
1174 .insert("uint8".to_string(), SolFormat::Primitive(Primitive::U8));
1175 }
1176 SolFormat::Primitive(Primitive::I16) => {
1177 self.names.insert(key_name, sol_format);
1178 self.names
1179 .insert("uint16".to_string(), SolFormat::Primitive(Primitive::U16));
1180 }
1181 SolFormat::Primitive(Primitive::I32) => {
1182 self.names.insert(key_name, sol_format);
1183 self.names
1184 .insert("uint32".to_string(), SolFormat::Primitive(Primitive::U32));
1185 }
1186 SolFormat::Primitive(Primitive::I64) => {
1187 self.names.insert(key_name, sol_format);
1188 self.names
1189 .insert("uint64".to_string(), SolFormat::Primitive(Primitive::U64));
1190 }
1191 SolFormat::Primitive(Primitive::I128) => {
1192 self.names.insert(key_name, sol_format);
1193 self.names
1194 .insert("uint128".to_string(), SolFormat::Primitive(Primitive::U128));
1195 }
1196 SolFormat::TypeName(_) => {
1197 }
1199 _ => {
1200 self.names.insert(key_name, sol_format);
1201 }
1202 }
1203 }
1204
1205 fn has_circular_dependency(&self) -> bool {
1206 for start_key in self.names.keys() {
1207 let mut level = HashSet::<String>::new();
1208 level.insert(start_key.to_string());
1209 let mut total_dependency = level.clone();
1210 loop {
1211 let mut new_level = HashSet::new();
1212 for key in level {
1213 for depend in self.names.get(&key).unwrap().get_dependency() {
1214 if depend == *start_key {
1215 return true;
1216 }
1217 if !total_dependency.contains(&depend) {
1218 total_dependency.insert(depend.clone());
1219 new_level.insert(depend);
1220 }
1221 }
1222 }
1223 if new_level.is_empty() {
1224 break;
1225 }
1226 level = new_level;
1227 }
1228 }
1229 false
1230 }
1231
1232 fn parse_format(&mut self, format: Format) -> SolFormat {
1233 use Format::*;
1234 let sol_format = match format {
1235 Variable(_) => panic!("variable is not supported in solidity"),
1236 TypeName(name) => SolFormat::TypeName(name),
1237 Unit => SolFormat::Primitive(Primitive::Unit),
1238 Bool => SolFormat::Primitive(Primitive::Bool),
1239 I8 => SolFormat::Primitive(Primitive::I8),
1240 I16 => SolFormat::Primitive(Primitive::I16),
1241 I32 => SolFormat::Primitive(Primitive::I32),
1242 I64 => SolFormat::Primitive(Primitive::I64),
1243 I128 => SolFormat::Primitive(Primitive::I128),
1244 U8 => SolFormat::Primitive(Primitive::U8),
1245 U16 => SolFormat::Primitive(Primitive::U16),
1246 U32 => SolFormat::Primitive(Primitive::U32),
1247 U64 => SolFormat::Primitive(Primitive::U64),
1248 U128 => SolFormat::Primitive(Primitive::U128),
1249 F32 => panic!("floating point is not supported in solidity"),
1250 F64 => panic!("floating point is not supported in solidity"),
1251 Char => SolFormat::Primitive(Primitive::Char),
1252 Str => SolFormat::Primitive(Primitive::Str),
1253 Bytes => SolFormat::Primitive(Primitive::Bytes),
1254 Option(format) => {
1255 let format = self.parse_format(*format);
1256 if format == SolFormat::Primitive(Primitive::Bool) {
1257 SolFormat::OptionBool
1258 } else {
1259 SolFormat::Option(Box::new(format))
1260 }
1261 }
1262 Seq(format) => {
1263 let format = self.parse_format(*format);
1264 SolFormat::Seq(Box::new(format))
1265 }
1266 Map { key, value } => {
1267 let key = self.parse_format(*key);
1268 let value = self.parse_format(*value);
1269 let name = format!("key_values_{}_{}", key.key_name(), value.key_name());
1270 let formats = vec![
1271 Named {
1272 name: "key".into(),
1273 value: key,
1274 },
1275 Named {
1276 name: "value".into(),
1277 value,
1278 },
1279 ];
1280 let sol_format = SolFormat::Struct { name, formats };
1281 self.insert(sol_format.clone());
1282 SolFormat::Seq(Box::new(sol_format))
1283 }
1284 Tuple(formats) => {
1285 let formats = formats
1286 .into_iter()
1287 .map(|format| self.parse_format(format))
1288 .collect::<Vec<_>>();
1289 let name = format!(
1290 "tuple_{}",
1291 formats
1292 .iter()
1293 .map(|format| format.key_name())
1294 .collect::<Vec<_>>()
1295 .join("_")
1296 );
1297 let formats = formats
1298 .into_iter()
1299 .enumerate()
1300 .map(|(idx, format)| Named {
1301 name: format!("entry{idx}"),
1302 value: format,
1303 })
1304 .collect();
1305 SolFormat::Struct { name, formats }
1306 }
1307 TupleArray { content, size } => {
1308 let format = self.parse_format(*content);
1309 if (1..=32).contains(&size) && format == SolFormat::Primitive(Primitive::U8) {
1310 SolFormat::BytesN { size }
1311 } else {
1312 SolFormat::TupleArray {
1313 format: Box::new(format),
1314 size,
1315 }
1316 }
1317 }
1318 };
1319 self.insert(sol_format.clone());
1320 sol_format
1321 }
1322
1323 fn parse_struct_format(&mut self, name: String, formats: Vec<Named<Format>>) -> SolFormat {
1324 let formats = formats
1325 .into_iter()
1326 .map(|named_format| Named {
1327 name: named_format.name,
1328 value: self.parse_format(named_format.value),
1329 })
1330 .collect();
1331 let sol_format = SolFormat::Struct { name, formats };
1332 self.insert(sol_format.clone());
1333 sol_format
1334 }
1335
1336 fn parse_container_format(&mut self, container_format: Named<ContainerFormat>) {
1337 use ContainerFormat::*;
1338 let name = container_format.name;
1339 let sol_format = match container_format.value {
1340 UnitStruct => panic!("UnitStruct is not supported in solidity"),
1341 NewTypeStruct(format) => {
1342 let format = Named {
1343 name: "value".to_string(),
1344 value: *format,
1345 };
1346 let formats = vec![format];
1347 self.parse_struct_format(name, formats)
1348 }
1349 TupleStruct(formats) => {
1350 assert!(
1351 !formats.is_empty(),
1352 "The TupleStruct should be non-trivial in solidity"
1353 );
1354 let formats = formats
1355 .into_iter()
1356 .enumerate()
1357 .map(|(idx, value)| Named {
1358 name: format!("entry{idx}"),
1359 value,
1360 })
1361 .collect();
1362 self.parse_struct_format(name, formats)
1363 }
1364 Struct(formats) => {
1365 assert!(
1366 !formats.is_empty(),
1367 "The struct should be non-trivial in solidity"
1368 );
1369 self.parse_struct_format(name, formats)
1370 }
1371 Enum(map) => {
1372 assert!(
1373 !map.is_empty(),
1374 "The enum should be non-trivial in solidity"
1375 );
1376 assert!(map.len() < 256, "The enum should have at most 256 entries");
1377 let is_trivial = map
1378 .iter()
1379 .all(|(_, v)| matches!(v.value, VariantFormat::Unit));
1380 if is_trivial {
1381 let names = map
1382 .into_values()
1383 .map(|named_format| named_format.name)
1384 .collect();
1385 SolFormat::SimpleEnum { name, names }
1386 } else {
1387 let choice_sol_format = SolFormat::Primitive(Primitive::U8);
1388 self.insert(choice_sol_format);
1389 let mut formats = Vec::new();
1390 for (_key, value) in map {
1391 use VariantFormat::*;
1392 let name_red = value.name;
1393 let concat_name = format!("{}_{}", name, name_red);
1394 let entry = match value.value {
1395 VariantFormat::Unit => None,
1396 NewType(format) => Some(self.parse_format(*format)),
1397 Tuple(formats) => {
1398 let formats = formats
1399 .into_iter()
1400 .enumerate()
1401 .map(|(idx, value)| Named {
1402 name: format!("entry{idx}"),
1403 value,
1404 })
1405 .collect::<Vec<_>>();
1406 Some(self.parse_struct_format(concat_name, formats))
1407 }
1408 Struct(formats) => Some(self.parse_struct_format(concat_name, formats)),
1409 Variable(_) => panic!("Variable is not supported for solidity"),
1410 };
1411 let format = Named {
1412 name: name_red,
1413 value: entry,
1414 };
1415 formats.push(format);
1416 }
1417 SolFormat::Enum { name, formats }
1418 }
1419 }
1420 };
1421 self.insert(sol_format);
1422 }
1423
1424 fn need_memory(&self, sol_format: &SolFormat) -> bool {
1425 use SolFormat::*;
1426 match sol_format {
1427 Primitive(primitive) => primitive.need_memory(),
1428 TypeName(name) => {
1429 let mesg = format!("to find a matching entry for name={name}");
1430 let sol_format = self.names.get(name).expect(&mesg);
1431 self.need_memory(sol_format)
1432 }
1433 Option(_) => true,
1434 Seq(_) => true,
1435 TupleArray { format: _, size: _ } => true,
1436 Struct {
1437 name: _,
1438 formats: _,
1439 } => true,
1440 SimpleEnum { name: _, names: _ } => false,
1441 Enum {
1442 name: _,
1443 formats: _,
1444 } => true,
1445 BytesN { size: _ } => false,
1446 OptionBool => false,
1447 }
1448 }
1449
1450 fn data_location(&self, sol_format: &SolFormat) -> String {
1451 get_data_location(self.need_memory(sol_format))
1452 }
1453}
1454
1455impl<'a> CodeGenerator<'a> {
1456 pub fn new(config: &'a CodeGeneratorConfig) -> Self {
1458 if config.c_style_enums {
1459 panic!("Solidity does not support generating c-style enums");
1460 }
1461 Self { config }
1462 }
1463
1464 pub fn output(
1465 &self,
1466 out: &mut dyn Write,
1467 registry: &Registry,
1468 ) -> std::result::Result<(), Box<dyn std::error::Error>> {
1469 let mut emitter = SolEmitter {
1470 out: IndentedWriter::new(out, IndentConfig::Space(4)),
1471 generator: self,
1472 };
1473
1474 emitter.output_license()?;
1475 emitter.output_open_library()?;
1476 emitter.output_preamble()?;
1477
1478 let mut sol_registry = SolRegistry::default();
1479 for (key, container_format) in registry {
1480 let container_format = Named {
1481 name: key.to_string(),
1482 value: container_format.clone(),
1483 };
1484 sol_registry.parse_container_format(container_format);
1485 }
1486 if sol_registry.has_circular_dependency() {
1487 panic!("solidity does not allow for circular dependencies");
1488 }
1489 for sol_format in sol_registry.names.values() {
1490 sol_format.output(&mut emitter.out, &sol_registry)?;
1491 }
1492
1493 emitter.output_close_library()?;
1494 Ok(())
1495 }
1496}
1497
1498impl<'a, T> SolEmitter<'a, T>
1499where
1500 T: std::io::Write,
1501{
1502 fn output_license(&mut self) -> Result<()> {
1503 writeln!(
1504 self.out,
1505 r#"/// SPDX-License-Identifier: UNLICENSED
1506pragma solidity ^0.8.0;"#
1507 )?;
1508 Ok(())
1509 }
1510
1511 fn output_preamble(&mut self) -> Result<()> {
1512 writeln!(
1513 self.out,
1514 r#"
1515function bcs_serialize_len(uint256 x)
1516 internal
1517 pure
1518 returns (bytes memory)
1519{{
1520 bytes memory result;
1521 bytes1 entry;
1522 while (true) {{
1523 if (x < 128) {{
1524 entry = bytes1(uint8(x));
1525 return abi.encodePacked(result, entry);
1526 }} else {{
1527 uint256 xb = x >> 7;
1528 uint256 remainder = x - (xb << 7);
1529 require(remainder < 128);
1530 entry = bytes1(uint8(remainder) + 128);
1531 result = abi.encodePacked(result, entry);
1532 x = xb;
1533 }}
1534 }}
1535 require(false, "This line is unreachable");
1536 return result;
1537}}
1538
1539function bcs_deserialize_offset_len(uint256 pos, bytes memory input)
1540 internal
1541 pure
1542 returns (uint256, uint256)
1543{{
1544 uint256 idx = 0;
1545 while (true) {{
1546 if (uint8(input[pos + idx]) < 128) {{
1547 uint256 result = 0;
1548 uint256 power = 1;
1549 for (uint256 u=0; u<idx; u++) {{
1550 uint8 val = uint8(input[pos + u]) - 128;
1551 result += power * uint256(val);
1552 power *= 128;
1553 }}
1554 result += power * uint8(input[pos + idx]);
1555 return (pos + idx + 1, result);
1556 }}
1557 idx += 1;
1558 }}
1559 require(false, "This line is unreachable");
1560 return (0,0);
1561}}"#
1562 )?;
1563 Ok(())
1564 }
1565
1566 fn output_open_library(&mut self) -> Result<()> {
1567 writeln!(
1568 self.out,
1569 "\nlibrary {} {{",
1570 self.generator.config.module_name
1571 )?;
1572 self.out.indent();
1573 Ok(())
1574 }
1575
1576 fn output_close_library(&mut self) -> Result<()> {
1577 self.out.unindent();
1578 writeln!(
1579 self.out,
1580 "\n}} // end of library {}",
1581 self.generator.config.module_name
1582 )?;
1583 Ok(())
1584 }
1585}
1586
1587pub struct Installer {
1589 install_dir: PathBuf,
1590}
1591
1592impl Installer {
1593 pub fn new(install_dir: PathBuf) -> Self {
1594 Installer { install_dir }
1595 }
1596
1597 fn create_header_file(&self, name: &str) -> Result<std::fs::File> {
1598 let dir_path = &self.install_dir;
1599 std::fs::create_dir_all(dir_path)?;
1600 std::fs::File::create(dir_path.join(name.to_string() + ".sol"))
1601 }
1602
1603 fn runtime_installation_message(name: &str) {
1604 eprintln!("Not installing sources for published crate {}", name);
1605 }
1606}
1607
1608impl crate::SourceInstaller for Installer {
1609 type Error = Box<dyn std::error::Error>;
1610
1611 fn install_module(
1612 &self,
1613 config: &crate::CodeGeneratorConfig,
1614 registry: &Registry,
1615 ) -> std::result::Result<(), Self::Error> {
1616 let mut file = self.create_header_file(&config.module_name)?;
1617 let generator = CodeGenerator::new(config);
1618 generator.output(&mut file, registry)
1619 }
1620
1621 fn install_serde_runtime(&self) -> std::result::Result<(), Self::Error> {
1622 Self::runtime_installation_message("serde");
1623 Ok(())
1624 }
1625
1626 fn install_bincode_runtime(&self) -> std::result::Result<(), Self::Error> {
1627 Self::runtime_installation_message("bincode");
1628 Ok(())
1629 }
1630
1631 fn install_bcs_runtime(&self) -> std::result::Result<(), Self::Error> {
1632 Self::runtime_installation_message("bcs");
1633 Ok(())
1634 }
1635}