difftreelog
doc(evm-coder): document public api
in: master
9 files changed
crates/evm-coder/Cargo.tomldiffbeforeafterboth5edition = "2021"5edition = "2021"667[dependencies]7[dependencies]8# evm-coder reexports those proc-macro8evm-coder-macros = { path = "../evm-coder-macros" }9evm-coder-procedural = { path = "./procedural" }10# Evm uses primitive-types for H160, H256 and others9primitive-types = { version = "0.11.1", default-features = false }11primitive-types = { version = "0.11.1", default-features = false }10hex-literal = "0.3.3"12# Evm doesn't have reexports for log and others11ethereum = { version = "0.12.0", default-features = false }13ethereum = { version = "0.12.0", default-features = false }14# Error types for execution12evm-core = { default-features = false, git = "https://github.com/uniquenetwork/evm", branch = "unique-polkadot-v0.9.27" }15evm-core = { default-features = false, git = "https://github.com/uniquenetwork/evm", branch = "unique-polkadot-v0.9.27" }16# We have tuple-heavy code in solidity.rs13impl-trait-for-tuples = "0.2.1"17impl-trait-for-tuples = "0.2.2"141815[dev-dependencies]19[dev-dependencies]20# We want to assert some large binary blobs equality in tests16hex = "0.4.3"21hex = "0.4.3"22hex-literal = "0.3.4"172318[features]24[features]19default = ["std"]25default = ["std"]crates/evm-coder/README.mddiffbeforeafterbothno changes
crates/evm-coder/procedural/Cargo.tomldiffbeforeafterboth8proc-macro = true8proc-macro = true9910[dependencies]10[dependencies]11# Ethereum uses keccak (=sha3) for selectors11sha3 = "0.10.1"12sha3 = "0.10.1"13# Value formatting14hex = "0.4.3"15Inflector = "0.11.4"16# General proc-macro utilities12quote = "1.0"17quote = "1.0"13proc-macro2 = "1.0"18proc-macro2 = "1.0"14syn = { version = "1.0", features = ["full"] }19syn = { version = "1.0", features = ["full"] }15hex = "0.4.3"16Inflector = "0.11.4"1720crates/evm-coder/procedural/src/lib.rsdiffbeforeafterboth199 Ident::new(&name, ident.span())199 Ident::new(&name, ident.span())200}200}201201202/// Derives call enum implementing [`evm_coder::Callable`], [`evm_coder::Weighted`]202/// See documentation for this proc-macro reexported in `evm-coder` crate203/// and [`evm_coder::Call`] from impl block204///205/// ## Macro syntax206///207/// `#[solidity_interface(name, is, inline_is, events)]`208/// - *name*: used in generated code, and for Call enum name209/// - *is*: used to provide call inheritance, not found methods will be delegated to all contracts210/// specified in is/inline_is211/// - *inline_is*: same as is, but selectors for passed contracts will be used by derived ERC165212/// implementation213///214/// `#[weight(value)]`215/// Can be added to every method of impl block, used for deriving [`evm_coder::Weighted`], which216/// is used by substrate bridge217/// - *value*: expression, which evaluates to weight required to call this method.218/// This expression can use call arguments to calculate non-constant execution time.219/// This expression should evaluate faster than actual execution does, and may provide worser case220/// than one is called221///222/// `#[solidity_interface(rename_selector)]`223/// - *rename_selector*: by default, selector name will be generated by transforming method name224/// from snake_case to camelCase. Use this option, if other naming convention is required.225/// I.e: method `token_uri` will be automatically renamed to `tokenUri` in selector, but name226/// required by ERC721 standard is `tokenURI`, thus we need to specify `rename_selector = "tokenURI"`227/// explicitly228///229/// Also, any contract method may have doc comments, which will be automatically added to generated230/// solidity interface definitions231///232/// ## Example233///234/// ```ignore235/// struct SuperContract;236/// struct InlineContract;237/// struct Contract;238///239/// #[derive(ToLog)]240/// enum ContractEvents {241/// Event(#[indexed] uint32),242/// }243///244/// #[solidity_interface(name = MyContract, is(SuperContract), inline_is(InlineContract))]245/// impl Contract {246/// /// Multiply two numbers247/// #[weight(200 + a + b)]248/// #[solidity_interface(rename_selector = "mul")]249/// fn mul(&mut self, a: uint32, b: uint32) -> Result<uint32> {250/// Ok(a.checked_mul(b).ok_or("overflow")?)251/// }252/// }253/// ```254#[proc_macro_attribute]203#[proc_macro_attribute]255pub fn solidity_interface(args: TokenStream, stream: TokenStream) -> TokenStream {204pub fn solidity_interface(args: TokenStream, stream: TokenStream) -> TokenStream {256 let args = parse_macro_input!(args as solidity_interface::InterfaceInfo);205 let args = parse_macro_input!(args as solidity_interface::InterfaceInfo);282 stream231 stream283}232}284233285/// ## Syntax234/// See documentation for this proc-macro reexported in `evm-coder` crate286///287/// `#[indexed]`288/// Marks this field as indexed, so it will appear in [`ethereum::Log`] topics instead of data289#[proc_macro_derive(ToLog, attributes(indexed))]235#[proc_macro_derive(ToLog, attributes(indexed))]290pub fn to_log(value: TokenStream) -> TokenStream {236pub fn to_log(value: TokenStream) -> TokenStream {291 let input = parse_macro_input!(value as DeriveInput);237 let input = parse_macro_input!(value as DeriveInput);crates/evm-coder/src/abi.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617//! TODO: I misunterstood therminology, abi IS rlp encoded, so17//! Implementation of EVM RLP reader/writer18//! this module should be replaced with rlp crate191820#![allow(dead_code)]19#![allow(dead_code)]2120323133const ABI_ALIGNMENT: usize = 32;32const ABI_ALIGNMENT: usize = 32;343334/// View into RLP data, which provides method to read typed items from it35#[derive(Clone)]35#[derive(Clone)]36pub struct AbiReader<'i> {36pub struct AbiReader<'i> {37 buf: &'i [u8],37 buf: &'i [u8],38 subresult_offset: usize,38 subresult_offset: usize,39 offset: usize,39 offset: usize,40}40}41impl<'i> AbiReader<'i> {41impl<'i> AbiReader<'i> {42 /// Start reading RLP buffer, assuming there is no padding bytes42 pub fn new(buf: &'i [u8]) -> Self {43 pub fn new(buf: &'i [u8]) -> Self {43 Self {44 Self {44 buf,45 buf,45 subresult_offset: 0,46 subresult_offset: 0,46 offset: 0,47 offset: 0,47 }48 }48 }49 }50 /// Start reading RLP buffer, parsing first 4 bytes as selector49 pub fn new_call(buf: &'i [u8]) -> Result<(types::bytes4, Self)> {51 pub fn new_call(buf: &'i [u8]) -> Result<(types::bytes4, Self)> {50 if buf.len() < 4 {52 if buf.len() < 4 {51 return Err(Error::Error(ExitError::OutOfOffset));53 return Err(Error::Error(ExitError::OutOfOffset));109 )111 )110 }112 }111113114 /// Read [`H160`] at current position, then advance112 pub fn address(&mut self) -> Result<H160> {115 pub fn address(&mut self) -> Result<H160> {113 Ok(H160(self.read_padleft()?))116 Ok(H160(self.read_padleft()?))114 }117 }115118119 /// Read [`bool`] at current position, then advance116 pub fn bool(&mut self) -> Result<bool> {120 pub fn bool(&mut self) -> Result<bool> {117 let data: [u8; 1] = self.read_padleft()?;121 let data: [u8; 1] = self.read_padleft()?;118 match data[0] {122 match data[0] {122 }126 }123 }127 }124128129 /// Read [`[u8; 4]`] at current position, then advance125 pub fn bytes4(&mut self) -> Result<[u8; 4]> {130 pub fn bytes4(&mut self) -> Result<[u8; 4]> {126 self.read_padright()131 self.read_padright()127 }132 }128133134 /// Read [`Vec<u8>`] at current position, then advance129 pub fn bytes(&mut self) -> Result<Vec<u8>> {135 pub fn bytes(&mut self) -> Result<Vec<u8>> {130 let mut subresult = self.subresult()?;136 let mut subresult = self.subresult()?;131 let length = subresult.read_usize()?;137 let length = subresult.uint32()? as usize;132 if subresult.buf.len() < subresult.offset + length {138 if subresult.buf.len() < subresult.offset + length {133 return Err(Error::Error(ExitError::OutOfOffset));139 return Err(Error::Error(ExitError::OutOfOffset));134 }140 }135 Ok(subresult.buf[subresult.offset..subresult.offset + length].into())141 Ok(subresult.buf[subresult.offset..subresult.offset + length].into())136 }142 }143144 /// Read [`string`] at current position, then advance137 pub fn string(&mut self) -> Result<string> {145 pub fn string(&mut self) -> Result<string> {138 string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))146 string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))139 }147 }140148149 /// Read [`u8`] at current position, then advance141 pub fn uint8(&mut self) -> Result<u8> {150 pub fn uint8(&mut self) -> Result<u8> {142 Ok(self.read_padleft::<1>()?[0])151 Ok(self.read_padleft::<1>()?[0])143 }152 }144153154 /// Read [`u32`] at current position, then advance145 pub fn uint32(&mut self) -> Result<u32> {155 pub fn uint32(&mut self) -> Result<u32> {146 Ok(u32::from_be_bytes(self.read_padleft()?))156 Ok(u32::from_be_bytes(self.read_padleft()?))147 }157 }148158159 /// Read [`u128`] at current position, then advance149 pub fn uint128(&mut self) -> Result<u128> {160 pub fn uint128(&mut self) -> Result<u128> {150 Ok(u128::from_be_bytes(self.read_padleft()?))161 Ok(u128::from_be_bytes(self.read_padleft()?))151 }162 }152163164 /// Read [`U256`] at current position, then advance153 pub fn uint256(&mut self) -> Result<U256> {165 pub fn uint256(&mut self) -> Result<U256> {154 let buf: [u8; 32] = self.read_padleft()?;166 let buf: [u8; 32] = self.read_padleft()?;155 Ok(U256::from_big_endian(&buf))167 Ok(U256::from_big_endian(&buf))156 }168 }157169170 /// Read [`u64`] at current position, then advance158 pub fn uint64(&mut self) -> Result<u64> {171 pub fn uint64(&mut self) -> Result<u64> {159 Ok(u64::from_be_bytes(self.read_padleft()?))172 Ok(u64::from_be_bytes(self.read_padleft()?))160 }173 }161174175 /// Read [`usize`] at current position, then advance176 #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]162 pub fn read_usize(&mut self) -> Result<usize> {177 pub fn read_usize(&mut self) -> Result<usize> {163 Ok(usize::from_be_bytes(self.read_padleft()?))178 Ok(usize::from_be_bytes(self.read_padleft()?))164 }179 }165180181 /// Slice recursive buffer, advance one word for buffer offset166 fn subresult(&mut self) -> Result<AbiReader<'i>> {182 fn subresult(&mut self) -> Result<AbiReader<'i>> {167 let offset = self.read_usize()?;183 let offset = self.uint32()? as usize;168 if offset + self.subresult_offset > self.buf.len() {184 if offset + self.subresult_offset > self.buf.len() {169 return Err(Error::Error(ExitError::InvalidRange));185 return Err(Error::Error(ExitError::InvalidRange));170 }186 }175 })191 })176 }192 }177193194 /// Is this parser reached end of buffer?178 pub fn is_finished(&self) -> bool {195 pub fn is_finished(&self) -> bool {179 self.buf.len() == self.offset196 self.buf.len() == self.offset180 }197 }181}198}182199200/// Writer for RLP encoded data183#[derive(Default)]201#[derive(Default)]184pub struct AbiWriter {202pub struct AbiWriter {185 static_part: Vec<u8>,203 static_part: Vec<u8>,186 dynamic_part: Vec<(usize, AbiWriter)>,204 dynamic_part: Vec<(usize, AbiWriter)>,187 had_call: bool,205 had_call: bool,188}206}189impl AbiWriter {207impl AbiWriter {208 /// Initialize internal buffers for output data, assuming no padding required190 pub fn new() -> Self {209 pub fn new() -> Self {191 Self::default()210 Self::default()192 }211 }212 /// Initialize internal buffers, inserting method selector at beginning193 pub fn new_call(method_id: u32) -> Self {213 pub fn new_call(method_id: u32) -> Self {194 let mut val = Self::new();214 let mut val = Self::new();195 val.static_part.extend(&method_id.to_be_bytes());215 val.static_part.extend(&method_id.to_be_bytes());211 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]);231 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]);212 }232 }213233234 /// Write [`H160`] to end of buffer214 pub fn address(&mut self, address: &H160) {235 pub fn address(&mut self, address: &H160) {215 self.write_padleft(&address.0)236 self.write_padleft(&address.0)216 }237 }217238239 /// Write [`bool`] to end of buffer218 pub fn bool(&mut self, value: &bool) {240 pub fn bool(&mut self, value: &bool) {219 self.write_padleft(&[if *value { 1 } else { 0 }])241 self.write_padleft(&[if *value { 1 } else { 0 }])220 }242 }221243244 /// Write [`u8`] to end of buffer222 pub fn uint8(&mut self, value: &u8) {245 pub fn uint8(&mut self, value: &u8) {223 self.write_padleft(&[*value])246 self.write_padleft(&[*value])224 }247 }225248249 /// Write [`u32`] to end of buffer226 pub fn uint32(&mut self, value: &u32) {250 pub fn uint32(&mut self, value: &u32) {227 self.write_padleft(&u32::to_be_bytes(*value))251 self.write_padleft(&u32::to_be_bytes(*value))228 }252 }229253254 /// Write [`u128`] to end of buffer230 pub fn uint128(&mut self, value: &u128) {255 pub fn uint128(&mut self, value: &u128) {231 self.write_padleft(&u128::to_be_bytes(*value))256 self.write_padleft(&u128::to_be_bytes(*value))232 }257 }233258259 /// Write [`U256`] to end of buffer234 pub fn uint256(&mut self, value: &U256) {260 pub fn uint256(&mut self, value: &U256) {235 let mut out = [0; 32];261 let mut out = [0; 32];236 value.to_big_endian(&mut out);262 value.to_big_endian(&mut out);237 self.write_padleft(&out)263 self.write_padleft(&out)238 }264 }239265266 /// Write [`usize`] to end of buffer267 #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]240 pub fn write_usize(&mut self, value: &usize) {268 pub fn write_usize(&mut self, value: &usize) {241 self.write_padleft(&usize::to_be_bytes(*value))269 self.write_padleft(&usize::to_be_bytes(*value))242 }270 }243271272 /// Append recursive data, writing pending offset at end of buffer244 pub fn write_subresult(&mut self, result: Self) {273 pub fn write_subresult(&mut self, result: Self) {245 self.dynamic_part.push((self.static_part.len(), result));274 self.dynamic_part.push((self.static_part.len(), result));246 // Empty block, to be filled later275 // Empty block, to be filled later247 self.write_padleft(&[]);276 self.write_padleft(&[]);248 }277 }249278250 pub fn memory(&mut self, value: &[u8]) {279 fn memory(&mut self, value: &[u8]) {251 let mut sub = Self::new();280 let mut sub = Self::new();252 sub.write_usize(&value.len());281 sub.uint32(&(value.len() as u32));253 for chunk in value.chunks(ABI_ALIGNMENT) {282 for chunk in value.chunks(ABI_ALIGNMENT) {254 sub.write_padright(chunk);283 sub.write_padright(chunk);255 }284 }256 self.write_subresult(sub);285 self.write_subresult(sub);257 }286 }258287288 /// Append recursive [`str`] at end of buffer259 pub fn string(&mut self, value: &str) {289 pub fn string(&mut self, value: &str) {260 self.memory(value.as_bytes())290 self.memory(value.as_bytes())261 }291 }262292293 /// Append recursive [`[u8]`] at end of buffer263 pub fn bytes(&mut self, value: &[u8]) {294 pub fn bytes(&mut self, value: &[u8]) {264 self.memory(value)295 self.memory(value)265 }296 }266297298 /// Finish writer, concatenating all internal buffers267 pub fn finish(mut self) -> Vec<u8> {299 pub fn finish(mut self) -> Vec<u8> {268 for (static_offset, part) in self.dynamic_part {300 for (static_offset, part) in self.dynamic_part {269 let part_offset = self.static_part.len() - self.had_call.then(|| 4).unwrap_or(0);301 let part_offset = self.static_part.len() - self.had_call.then(|| 4).unwrap_or(0);278 }310 }279}311}280312313/// [`AbiReader`] implements reading of many types, but it should314/// be limited to types defined in spec315///316/// As this trait can't be made sealed,317/// instead of having `impl AbiRead for T`, we have `impl AbiRead<T> for AbiReader`281pub trait AbiRead<T> {318pub trait AbiRead<T> {319 /// Read item from current position, advanding decoder282 fn abi_read(&mut self) -> Result<T>;320 fn abi_read(&mut self) -> Result<T>;283}321}284322318{356{319 fn abi_read(&mut self) -> Result<Vec<R>> {357 fn abi_read(&mut self) -> Result<Vec<R>> {320 let mut sub = self.subresult()?;358 let mut sub = self.subresult()?;321 let size = sub.read_usize()?;359 let size = sub.uint32()? as usize;322 sub.subresult_offset = sub.offset;360 sub.subresult_offset = sub.offset;323 let mut out = Vec::with_capacity(size);361 let mut out = Vec::with_capacity(size);324 for _ in 0..size {362 for _ in 0..size {366impl_tuples! {A B C D E F G H I}404impl_tuples! {A B C D E F G H I}367impl_tuples! {A B C D E F G H I J}405impl_tuples! {A B C D E F G H I J}368406407/// For questions about inability to provide custom implementations,408/// see [`AbiRead`]369pub trait AbiWrite {409pub trait AbiWrite {410 /// Write value to end of specified encoder370 fn abi_write(&self, writer: &mut AbiWriter);411 fn abi_write(&self, writer: &mut AbiWriter);412 /// Specialization for [`crate::solidity_interface`] implementation,413 /// see comment in `impl AbiWrite for ResultWithPostInfo`371 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {414 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {372 let mut writer = AbiWriter::new();415 let mut writer = AbiWriter::new();373 self.abi_write(&mut writer);416 self.abi_write(&mut writer);374 Ok(writer.into())417 Ok(writer.into())375 }418 }376}419}377420421/// This particular AbiWrite implementation should be split to another trait,422/// which only implements `to_result`, but due to lack of specialization feature423/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,424/// so here we abusing default trait methods for it378impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {425impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {379 // this particular AbiWrite implementation should be split to another trait,380 // which only implements [`to_result`]381 //382 // But due to lack of specialization feature in stable Rust, we can't have383 // blanket impl of this trait `for T where T: AbiWrite`, so here we abusing384 // default trait methods for it385 fn abi_write(&self, _writer: &mut AbiWriter) {426 fn abi_write(&self, _writer: &mut AbiWriter) {386 debug_assert!(false, "shouldn't be called, see comment")427 debug_assert!(false, "shouldn't be called, see comment")387 }428 }432 fn abi_write(&self, _writer: &mut AbiWriter) {}473 fn abi_write(&self, _writer: &mut AbiWriter) {}433}474}434475476/// Helper macros to parse reader into variables477#[deprecated]435#[macro_export]478#[macro_export]436macro_rules! abi_decode {479macro_rules! abi_decode {437 ($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {480 ($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {441 }484 }442}485}486487/// Helper macros to construct RLP-encoded buffer488#[deprecated]443#[macro_export]489#[macro_export]444macro_rules! abi_encode {490macro_rules! abi_encode {445 ($($typ:ident($value:expr)),* $(,)?) => {{491 ($($typ:ident($value:expr)),* $(,)?) => {{crates/evm-coder/src/events.rsdiffbeforeafterboth191920use crate::types::*;20use crate::types::*;212122/// Implementation of this trait should not be written manually,23/// instead use [`crate::ToLog`] proc macros.24///25/// See also [`evm_coder_procedural::ToLog`], [solidity docs on events](https://docs.soliditylang.org/en/develop/contracts.html#events)22pub trait ToLog {26pub trait ToLog {27 /// Convert event to [`ethereum::Log`].28 /// Because event by itself doesn't contains current contract29 /// address, it should be specified manually.23 fn to_log(&self, contract: H160) -> Log;30 fn to_log(&self, contract: H160) -> Log;24}31}253233/// Only items implementing `ToTopic` may be used as `#[indexed]` field34/// in [`crate::ToLog`] macro usage.35///36/// See also (solidity docs on events)[<https://docs.soliditylang.org/en/develop/contracts.html#events>]26pub trait ToTopic {37pub trait ToTopic {38 /// Convert value to topic to be used in [`ethereum::Log`]27 fn to_topic(&self) -> H256;39 fn to_topic(&self) -> H256;28}40}2941crates/evm-coder/src/execution.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Contract execution related types161817#[cfg(not(feature = "std"))]19#[cfg(not(feature = "std"))]18use alloc::string::{String, ToString};20use alloc::string::{String, ToString};222423use crate::Weight;25use crate::Weight;242627/// Execution error, should be convertible between EVM and Substrate.25#[derive(Debug, Clone)]28#[derive(Debug, Clone)]26pub enum Error {29pub enum Error {30 /// Non-fatal contract error occured27 Revert(String),31 Revert(String),32 /// EVM fatal error28 Fatal(ExitFatal),33 Fatal(ExitFatal),34 /// EVM normal error29 Error(ExitError),35 Error(ExitError),30}36}313738 }44 }39}45}404647/// To be used in [`crate::solidity_interface`] implementation.41pub type Result<T> = core::result::Result<T, Error>;48pub type Result<T> = core::result::Result<T, Error>;424950/// Static information collected from [`crate::weight`].43pub struct DispatchInfo {51pub struct DispatchInfo {52 /// Statically predicted call weight44 pub weight: Weight,53 pub weight: Weight,45}54}465555 }64 }56}65}576667/// Weight information that is only available post dispatch.68/// Note: This can only be used to reduce the weight or fee, not increase it.58#[derive(Default, Clone)]69#[derive(Default, Clone)]59pub struct PostDispatchInfo {70pub struct PostDispatchInfo {71 /// Actual weight consumed by call60 actual_weight: Option<Weight>,72 actual_weight: Option<Weight>,61}73}627463impl PostDispatchInfo {75impl PostDispatchInfo {76 /// Calculate amount to be returned back to user64 pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight {77 pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight {65 info.weight - self.calc_actual_weight(info)78 info.weight - self.calc_actual_weight(info)66 }79 }678081 /// Calculate actual cansumed weight, saturating to weight reported82 /// pre-dispatch68 pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight {83 pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight {69 if let Some(actual_weight) = self.actual_weight {84 if let Some(actual_weight) = self.actual_weight {70 actual_weight.min(info.weight)85 actual_weight.min(info.weight)74 }89 }75}90}769192/// Wrapper for PostDispatchInfo and any user-provided data77#[derive(Clone)]93#[derive(Clone)]78pub struct WithPostDispatchInfo<T> {94pub struct WithPostDispatchInfo<T> {95 /// User provided data79 pub data: T,96 pub data: T,97 /// Info known after dispatch80 pub post_info: PostDispatchInfo,98 pub post_info: PostDispatchInfo,81}99}8210089 }107 }90}108}91109110/// Return type of items in [`crate::solidity_interface`] definition92pub type ResultWithPostInfo<T> =111pub type ResultWithPostInfo<T> =93 core::result::Result<WithPostDispatchInfo<T>, WithPostDispatchInfo<Error>>;112 core::result::Result<WithPostDispatchInfo<T>, WithPostDispatchInfo<Error>>;94113crates/evm-coder/src/lib.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617#![doc = include_str!("../README.md")]18#![deny(missing_docs)]17#![cfg_attr(not(feature = "std"), no_std)]19#![cfg_attr(not(feature = "std"), no_std)]18#[cfg(not(feature = "std"))]20#[cfg(not(feature = "std"))]19extern crate alloc;21extern crate alloc;202221use abi::{AbiRead, AbiReader, AbiWriter};23use abi::{AbiRead, AbiReader, AbiWriter};22pub use evm_coder_macros::{event_topic, fn_selector, solidity_interface, solidity, weight, ToLog};24pub use evm_coder_procedural::{event_topic, fn_selector};23pub mod abi;25pub mod abi;24pub mod events;25pub use events::ToLog;26pub use events::{ToLog, ToTopic};26use execution::DispatchInfo;27use execution::DispatchInfo;27pub mod execution;28pub mod execution;2930/// Derives call enum implementing [`crate::Callable`], [`crate::Weighted`]31/// and [`crate::Call`] from impl block.32///33/// ## Macro syntax34///35/// `#[solidity_interface(name, is, inline_is, events)]`36/// - *name* - used in generated code, and for Call enum name37/// - *is* - used to provide call inheritance, not found methods will be delegated to all contracts38/// specified in is/inline_is39/// - *inline_is* - same as is, but selectors for passed contracts will be used by derived ERC16540/// implementation41///42/// `#[weight(value)]`43/// Can be added to every method of impl block, used for deriving [`crate::Weighted`], which44/// is used by substrate bridge.45/// - *value*: expression, which evaluates to weight required to call this method.46/// This expression can use call arguments to calculate non-constant execution time.47/// This expression should evaluate faster than actual execution does, and may provide worser case48/// than one is called.49///50/// `#[solidity_interface(rename_selector)]`51/// - *rename_selector* - by default, selector name will be generated by transforming method name52/// from snake_case to camelCase. Use this option, if other naming convention is required.53/// I.e: method `token_uri` will be automatically renamed to `tokenUri` in selector, but name54/// required by ERC721 standard is `tokenURI`, thus we need to specify `rename_selector = "tokenURI"`55/// explicitly.56///57/// Both contract and contract methods may have doccomments, which will end up in a generated58/// solidity interface file, thus you should use [solidity syntax](https://docs.soliditylang.org/en/latest/natspec-format.html) for writing documentation in this macro59///60/// ## Example61///62/// ```ignore63/// struct SuperContract;64/// struct InlineContract;65/// struct Contract;66///67/// #[derive(ToLog)]68/// enum ContractEvents {69/// Event(#[indexed] uint32),70/// }71///72/// /// @dev This contract provides function to multiply two numbers73/// #[solidity_interface(name = MyContract, is(SuperContract), inline_is(InlineContract))]74/// impl Contract {75/// /// Multiply two numbers76/// /// @param a First number77/// /// @param b Second number78/// /// @return uint32 Product of two passed numbers79/// /// @dev This function returns error in case of overflow80/// #[weight(200 + a + b)]81/// #[solidity_interface(rename_selector = "mul")]82/// fn mul(&mut self, a: uint32, b: uint32) -> Result<uint32> {83/// Ok(a.checked_mul(b).ok_or("overflow")?)84/// }85/// }86/// ```87pub use evm_coder_procedural::solidity_interface;88/// See [`solidity_interface`]89pub use evm_coder_procedural::solidity;90/// See [`solidity_interface`]91pub use evm_coder_procedural::weight;9293/// Derives [`ToLog`] for enum94///95/// Selectors will be derived from variant names, there is currently no way to have custom naming96/// for them97///98/// `#[indexed]`99/// Marks this field as indexed, so it will appear in [`ethereum::Log`] topics instead of data100pub use evm_coder_procedural::ToLog;101102// Api of those modules shouldn't be consumed directly, it is only exported for usage in proc macros103#[doc(hidden)]104pub mod events;105#[doc(hidden)]28pub mod solidity;106pub mod solidity;2910730/// Solidity type definitions108/// Solidity type definitions (aliases from solidity name to rust type)109/// To be used in [`solidity_interface`] definitions, to make sure there is no110/// type conflict between Rust code and generated definitions31pub mod types {111pub mod types {32 #![allow(non_camel_case_types)]112 #![allow(non_camel_case_types, missing_docs)]3311334 #[cfg(not(feature = "std"))]114 #[cfg(not(feature = "std"))]35 use alloc::{vec::Vec};115 use alloc::{vec::Vec};54 pub type string = ::std::string::String;134 pub type string = ::std::string::String;55 pub type bytes = Vec<u8>;135 pub type bytes = Vec<u8>;56136137 /// Solidity doesn't have `void` type, however we have special implementation138 /// for empty tuple return type57 pub type void = ();139 pub type void = ();5814059 //#region Special types141 //#region Special types63 pub type caller = address;145 pub type caller = address;64 //#endregion146 //#endregion65147148 /// Ethereum typed call message, similar to solidity149 /// `msg` object.66 pub struct Msg<C> {150 pub struct Msg<C> {67 pub call: C,151 pub call: C,152 /// Address of user, which called this contract.68 pub caller: H160,153 pub caller: H160,154 /// Payment amount to contract.155 /// Contract should reject payment, if target call is not payable,156 /// and there is no `receiver()` function defined.69 pub value: U256,157 pub value: U256,70 }158 }71}159}72160161/// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macro73pub trait Call: Sized {162pub trait Call: Sized {163 /// Parse call buffer into typed call enum74 fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>>;164 fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>>;75}165}76166167/// Intended to be used as `#[weight]` output type168/// Should be same between evm-coder and substrate to avoid confusion169///170/// Isn't same thing as gas, some mapping is required between those types77pub type Weight = u64;171pub type Weight = u64;78172173/// In substrate, we have benchmarking, which allows174/// us to not rely on gas metering, but instead predict amount of gas to execute call79pub trait Weighted: Call {175pub trait Weighted: Call {176 /// Predict weight of this call80 fn weight(&self) -> DispatchInfo;177 fn weight(&self) -> DispatchInfo;81}178}82179180/// Type callable with ethereum message, may be implemented by [`solidity_interface`] macro181/// on interface implementation, or for externally-owned real EVM contract83pub trait Callable<C: Call> {182pub trait Callable<C: Call> {183 /// Call contract using specified call data84 fn call(&mut self, call: types::Msg<C>) -> execution::ResultWithPostInfo<AbiWriter>;184 fn call(&mut self, call: types::Msg<C>) -> execution::ResultWithPostInfo<AbiWriter>;85}185}8618687/// Implementation is implicitly provided for all interfaces187/// Implementation of ERC165 is implicitly generated for all interfaces in [`solidity_interface`],188/// this structure holds parsed data for ERC165Call subvariant88///189///89/// Note: no Callable implementation is provided190/// Note: no [`Callable`] implementation is provided, call implementation is inlined into every191/// implementing contract192///193/// See <https://eips.ethereum.org/EIPS/eip-165>90#[derive(Debug)]194#[derive(Debug)]91pub enum ERC165Call {195pub enum ERC165Call {196 /// ERC165 provides single method, which returns true, if contract197 /// implements specified interface92 SupportsInterface { interface_id: types::bytes4 },198 SupportsInterface {199 /// Requested interface200 interface_id: types::bytes4,201 },93}202}9420395impl ERC165Call {204impl ERC165Call {205 /// ERC165 selector is provided by standard96 pub const INTERFACE_ID: types::bytes4 = u32::to_be_bytes(0x01ffc9a7);206 pub const INTERFACE_ID: types::bytes4 = u32::to_be_bytes(0x01ffc9a7);97}207}98208crates/evm-coder/src/solidity.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617//! Implementation detail of [`evm_coder::solidity_interface`] macro code-generation17//! Implementation detail of [`crate::solidity_interface`] macro code-generation.18//! You should not rely on any public item from this module, as it is only intended to be used19//! by procedural macro, API and output format may be changed at any time.20//!21//! Purpose of this module is to receive solidity contract definition in module-specified22//! format, and then output string, representing interface of this contract in solidity language182319#[cfg(not(feature = "std"))]24#[cfg(not(feature = "std"))]20use alloc::{25use alloc::{string::String, vec::Vec, collections::BTreeMap, format};21 string::String,22 vec::Vec,23 collections::BTreeMap,24 format,25};26#[cfg(feature = "std")]26#[cfg(feature = "std")]27use std::collections::BTreeMap;27use std::collections::BTreeMap;818182pub trait SolidityTypeName: 'static {82pub trait SolidityTypeName: 'static {83 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;83 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;84 /// "simple" types are stored inline, no `memory` modifier should be used in solidity84 fn is_simple() -> bool;85 fn is_simple() -> bool;85 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;86 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;87 /// Specialization86 fn is_void() -> bool {88 fn is_void() -> bool {87 false89 false88 }90 }133}135}134136135mod sealed {137mod sealed {138 /// Not every type should be directly placed in vec.139 /// Vec encoding is not memory efficient, as every item will be padded140 /// to 32 bytes.141 /// Instead you should use specialized types (`bytes` in case of `Vec<u8>`)136 pub trait CanBePlacedInVec {}142 pub trait CanBePlacedInVec {}137}143}138144