git.delta.rocks / unique-network / refs/commits / c8aac156edde

difftreelog

source

crates/evm-coder/src/solidity.rs13.2 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#[cfg(not(feature = "std"))]18use alloc::{19	string::String,20	vec::Vec,21	collections::{BTreeSet, BTreeMap},22	format,23};24#[cfg(feature = "std")]25use std::collections::{BTreeSet, BTreeMap};26use core::{27	fmt::{self, Write},28	marker::PhantomData,29	cell::{Cell, RefCell},30};31use impl_trait_for_tuples::impl_for_tuples;32use crate::types::*;3334#[derive(Default)]35pub struct TypeCollector {36	structs: RefCell<BTreeSet<string>>,37	anonymous: RefCell<BTreeMap<Vec<string>, usize>>,38	id: Cell<usize>,39}40impl TypeCollector {41	pub fn new() -> Self {42		Self::default()43	}44	pub fn collect(&self, item: string) {45		self.structs.borrow_mut().insert(item);46	}47	pub fn next_id(&self) -> usize {48		let v = self.id.get();49		self.id.set(v + 1);50		v51	}52	pub fn collect_tuple<T: SolidityTupleType>(&self) -> String {53		let names = T::names(self);54		if let Some(id) = self.anonymous.borrow().get(&names).cloned() {55			return format!("Tuple{}", id);56		}57		let id = self.next_id();58		let mut str = String::new();59		writeln!(str, "// Anonymous struct").unwrap();60		writeln!(str, "struct Tuple{} {{", id).unwrap();61		for (i, name) in names.iter().enumerate() {62			writeln!(str, "\t{} field_{};", name, i).unwrap();63		}64		writeln!(str, "}}").unwrap();65		self.collect(str);66		self.anonymous.borrow_mut().insert(names, id);67		format!("Tuple{}", id)68	}69	pub fn finish(self) -> BTreeSet<string> {70		self.structs.into_inner()71	}72}7374pub trait SolidityTypeName: 'static {75	fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;76	fn is_simple() -> bool;77	fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;78	fn is_void() -> bool {79		false80	}81}82macro_rules! solidity_type_name {83    ($($ty:ty => $name:literal $simple:literal = $default:literal),* $(,)?) => {84        $(85            impl SolidityTypeName for $ty {86                fn solidity_name(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result {87                    write!(writer, $name)88                }89				fn is_simple() -> bool {90					$simple91				}92				fn solidity_default(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result {93					write!(writer, $default)94				}95            }96        )*97    };98}99100solidity_type_name! {101	uint8 => "uint8" true = "0",102	uint32 => "uint32" true = "0",103	uint64 => "uint64" true = "0",104	uint128 => "uint128" true = "0",105	uint256 => "uint256" true = "0",106	address => "address" true = "0x0000000000000000000000000000000000000000",107	string => "string" false = "\"\"",108	bytes => "bytes" false = "hex\"\"",109	bool => "bool" true = "false",110}111impl SolidityTypeName for void {112	fn solidity_name(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {113		Ok(())114	}115	fn is_simple() -> bool {116		true117	}118	fn solidity_default(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {119		Ok(())120	}121	fn is_void() -> bool {122		true123	}124}125126mod sealed {127	pub trait CanBePlacedInVec {}128}129130impl sealed::CanBePlacedInVec for uint256 {}131impl sealed::CanBePlacedInVec for string {}132impl sealed::CanBePlacedInVec for address {}133134impl<T: SolidityTypeName + sealed::CanBePlacedInVec> SolidityTypeName for Vec<T> {135	fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {136		T::solidity_name(writer, tc)?;137		write!(writer, "[]")138	}139	fn is_simple() -> bool {140		false141	}142	fn solidity_default(writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {143		write!(writer, "[]")144	}145}146147pub trait SolidityTupleType {148	fn names(tc: &TypeCollector) -> Vec<String>;149	fn len() -> usize;150}151152macro_rules! count {153    () => (0usize);154    ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));155}156157macro_rules! impl_tuples {158	($($ident:ident)+) => {159		impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}160		impl<$($ident: SolidityTypeName + 'static),+> SolidityTupleType for ($($ident,)+) {161			fn names(tc: &TypeCollector) -> Vec<string> {162				let mut collected = Vec::with_capacity(Self::len());163				$({164					let mut out = string::new();165					$ident::solidity_name(&mut out, tc).expect("no fmt error");166					collected.push(out);167				})*;168				collected169			}170171			fn len() -> usize {172				count!($($ident)*)173			}174		}175		impl<$($ident: SolidityTypeName + 'static),+> SolidityTypeName for ($($ident,)+) {176			fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {177				write!(writer, "{}", tc.collect_tuple::<Self>())178			}179			fn is_simple() -> bool {180				false181			}182			fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {183				write!(writer, "{}(", tc.collect_tuple::<Self>())?;184				$(185					<$ident>::solidity_default(writer, tc)?;186				)*187				write!(writer, ")")188			}189		}190	};191}192193impl_tuples! {A}194impl_tuples! {A B}195impl_tuples! {A B C}196impl_tuples! {A B C D}197impl_tuples! {A B C D E}198impl_tuples! {A B C D E F}199impl_tuples! {A B C D E F G}200impl_tuples! {A B C D E F G H}201impl_tuples! {A B C D E F G H I}202impl_tuples! {A B C D E F G H I J}203204pub trait SolidityArguments {205	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;206	fn solidity_get(&self, writer: &mut impl fmt::Write) -> fmt::Result;207	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;208	fn is_empty(&self) -> bool {209		self.len() == 0210	}211	fn len(&self) -> usize;212}213214#[derive(Default)]215pub struct UnnamedArgument<T>(PhantomData<*const T>);216217impl<T: SolidityTypeName> SolidityArguments for UnnamedArgument<T> {218	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {219		if !T::is_void() {220			T::solidity_name(writer, tc)?;221			if !T::is_simple() {222				write!(writer, " memory")?;223			}224			Ok(())225		} else {226			Ok(())227		}228	}229	fn solidity_get(&self, _writer: &mut impl fmt::Write) -> fmt::Result {230		Ok(())231	}232	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {233		T::solidity_default(writer, tc)234	}235	fn len(&self) -> usize {236		if T::is_void() {237			0238		} else {239			1240		}241	}242}243244pub struct NamedArgument<T>(&'static str, PhantomData<*const T>);245246impl<T> NamedArgument<T> {247	pub fn new(name: &'static str) -> Self {248		Self(name, Default::default())249	}250}251252impl<T: SolidityTypeName> SolidityArguments for NamedArgument<T> {253	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {254		if !T::is_void() {255			T::solidity_name(writer, tc)?;256			if !T::is_simple() {257				write!(writer, " memory")?;258			}259			write!(writer, " {}", self.0)260		} else {261			Ok(())262		}263	}264	fn solidity_get(&self, writer: &mut impl fmt::Write) -> fmt::Result {265		writeln!(writer, "\t\t{};", self.0)266	}267	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {268		T::solidity_default(writer, tc)269	}270	fn len(&self) -> usize {271		if T::is_void() {272			0273		} else {274			1275		}276	}277}278279pub struct SolidityEventArgument<T>(pub bool, &'static str, PhantomData<*const T>);280281impl<T> SolidityEventArgument<T> {282	pub fn new(indexed: bool, name: &'static str) -> Self {283		Self(indexed, name, Default::default())284	}285}286287impl<T: SolidityTypeName> SolidityArguments for SolidityEventArgument<T> {288	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {289		if !T::is_void() {290			T::solidity_name(writer, tc)?;291			if self.0 {292				write!(writer, " indexed")?;293			}294			write!(writer, " {}", self.1)295		} else {296			Ok(())297		}298	}299	fn solidity_get(&self, writer: &mut impl fmt::Write) -> fmt::Result {300		writeln!(writer, "\t\t{};", self.1)301	}302	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {303		T::solidity_default(writer, tc)304	}305	fn len(&self) -> usize {306		if T::is_void() {307			0308		} else {309			1310		}311	}312}313314impl SolidityArguments for () {315	fn solidity_name(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {316		Ok(())317	}318	fn solidity_get(&self, _writer: &mut impl fmt::Write) -> fmt::Result {319		Ok(())320	}321	fn solidity_default(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {322		Ok(())323	}324	fn len(&self) -> usize {325		0326	}327}328329#[impl_for_tuples(1, 5)]330impl SolidityArguments for Tuple {331	for_tuples!( where #( Tuple: SolidityArguments ),* );332333	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {334		let mut first = true;335		for_tuples!( #(336            if !Tuple.is_empty() {337                if !first {338                    write!(writer, ", ")?;339                }340                first = false;341                Tuple.solidity_name(writer, tc)?;342            }343        )* );344		Ok(())345	}346	fn solidity_get(&self, writer: &mut impl fmt::Write) -> fmt::Result {347		for_tuples!( #(348            Tuple.solidity_get(writer)?;349        )* );350		Ok(())351	}352	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {353		if self.is_empty() {354			Ok(())355		} else if self.len() == 1 {356			for_tuples!( #(357				Tuple.solidity_default(writer, tc)?;358			)* );359			Ok(())360		} else {361			write!(writer, "(")?;362			let mut first = true;363			for_tuples!( #(364				if !Tuple.is_empty() {365					if !first {366						write!(writer, ", ")?;367					}368					first = false;369					Tuple.solidity_default(writer, tc)?;370				}371			)* );372			write!(writer, ")")?;373			Ok(())374		}375	}376	fn len(&self) -> usize {377		for_tuples!( #( Tuple.len() )+* )378	}379}380381pub trait SolidityFunctions {382	fn solidity_name(383		&self,384		is_impl: bool,385		writer: &mut impl fmt::Write,386		tc: &TypeCollector,387	) -> fmt::Result;388}389390pub enum SolidityMutability {391	Pure,392	View,393	Mutable,394}395pub struct SolidityFunction<A, R> {396	pub docs: &'static [&'static str],397	pub selector: &'static str,398	pub name: &'static str,399	pub args: A,400	pub result: R,401	pub mutability: SolidityMutability,402}403impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {404	fn solidity_name(405		&self,406		is_impl: bool,407		writer: &mut impl fmt::Write,408		tc: &TypeCollector,409	) -> fmt::Result {410		for doc in self.docs {411			writeln!(writer, "\t//{}", doc)?;412		}413		if !self.docs.is_empty() {414			writeln!(writer, "\t//")?;415		}416		writeln!(writer, "\t// Selector: {}", self.selector)?;417		write!(writer, "\tfunction {}(", self.name)?;418		self.args.solidity_name(writer, tc)?;419		write!(writer, ")")?;420		if is_impl {421			write!(writer, " public")?;422		} else {423			write!(writer, " external")?;424		}425		match &self.mutability {426			SolidityMutability::Pure => write!(writer, " pure")?,427			SolidityMutability::View => write!(writer, " view")?,428			SolidityMutability::Mutable => {}429		}430		if !self.result.is_empty() {431			write!(writer, " returns (")?;432			self.result.solidity_name(writer, tc)?;433			write!(writer, ")")?;434		}435		if is_impl {436			writeln!(writer, " {{")?;437			writeln!(writer, "\t\trequire(false, stub_error);")?;438			self.args.solidity_get(writer)?;439			match &self.mutability {440				SolidityMutability::Pure => {}441				SolidityMutability::View => writeln!(writer, "\t\tdummy;")?,442				SolidityMutability::Mutable => writeln!(writer, "\t\tdummy = 0;")?,443			}444			if !self.result.is_empty() {445				write!(writer, "\t\treturn ")?;446				self.result.solidity_default(writer, tc)?;447				writeln!(writer, ";")?;448			}449			writeln!(writer, "\t}}")?;450		} else {451			writeln!(writer, ";")?;452		}453		Ok(())454	}455}456457#[impl_for_tuples(0, 12)]458impl SolidityFunctions for Tuple {459	for_tuples!( where #( Tuple: SolidityFunctions ),* );460461	fn solidity_name(462		&self,463		is_impl: bool,464		writer: &mut impl fmt::Write,465		tc: &TypeCollector,466	) -> fmt::Result {467		let mut first = false;468		for_tuples!( #(469            Tuple.solidity_name(is_impl, writer, tc)?;470        )* );471		Ok(())472	}473}474475pub struct SolidityInterface<F: SolidityFunctions> {476	pub selector: u32,477	pub name: &'static str,478	pub is: &'static [&'static str],479	pub functions: F,480}481482impl<F: SolidityFunctions> SolidityInterface<F> {483	pub fn format(484		&self,485		is_impl: bool,486		out: &mut impl fmt::Write,487		tc: &TypeCollector,488	) -> fmt::Result {489		if self.selector != 0 {490			writeln!(out, "// Selector: {:0>8x}", self.selector)?;491		}492		if is_impl {493			write!(out, "contract ")?;494		} else {495			write!(out, "interface ")?;496		}497		write!(out, "{}", self.name)?;498		if !self.is.is_empty() {499			write!(out, " is")?;500			for (i, n) in self.is.iter().enumerate() {501				if i != 0 {502					write!(out, ",")?;503				}504				write!(out, " {}", n)?;505			}506		}507		writeln!(out, " {{")?;508		self.functions.solidity_name(is_impl, out, tc)?;509		writeln!(out, "}}")?;510		Ok(())511	}512}513514pub struct SolidityEvent<A> {515	pub name: &'static str,516	pub args: A,517}518519impl<A: SolidityArguments> SolidityFunctions for SolidityEvent<A> {520	fn solidity_name(521		&self,522		_is_impl: bool,523		writer: &mut impl fmt::Write,524		tc: &TypeCollector,525	) -> fmt::Result {526		write!(writer, "\tevent {}(", self.name)?;527		self.args.solidity_name(writer, tc)?;528		writeln!(writer, ");")529	}530}