difftreelog
doc(evm-coder): document public api
in: master
9 files changed
crates/evm-coder/Cargo.tomldiffbeforeafterboth--- a/crates/evm-coder/Cargo.toml
+++ b/crates/evm-coder/Cargo.toml
@@ -5,15 +5,21 @@
edition = "2021"
[dependencies]
-evm-coder-macros = { path = "../evm-coder-macros" }
+# evm-coder reexports those proc-macro
+evm-coder-procedural = { path = "./procedural" }
+# Evm uses primitive-types for H160, H256 and others
primitive-types = { version = "0.11.1", default-features = false }
-hex-literal = "0.3.3"
+# Evm doesn't have reexports for log and others
ethereum = { version = "0.12.0", default-features = false }
+# Error types for execution
evm-core = { default-features = false, git = "https://github.com/uniquenetwork/evm", branch = "unique-polkadot-v0.9.27" }
-impl-trait-for-tuples = "0.2.1"
+# We have tuple-heavy code in solidity.rs
+impl-trait-for-tuples = "0.2.2"
[dev-dependencies]
+# We want to assert some large binary blobs equality in tests
hex = "0.4.3"
+hex-literal = "0.3.4"
[features]
default = ["std"]
crates/evm-coder/README.mddiffbeforeafterboth--- /dev/null
+++ b/crates/evm-coder/README.md
@@ -0,0 +1,15 @@
+# evm-coder
+
+Library for seamless call translation between Rust and Solidity code
+
+By encoding solidity definitions in Rust, this library also provides generation of
+solidity interfaces for ethereum developers
+
+## Overview
+
+Most of this library functionality shouldn't be used directly, but via macros
+
+- [`solidity_interface`]
+- [`ToLog`]
+
+<!-- TODO: make links useable on github, by publishing crate to docs.rs, and linking it from here instead -->
\ No newline at end of file
crates/evm-coder/procedural/Cargo.tomldiffbeforeafterboth--- a/crates/evm-coder/procedural/Cargo.toml
+++ b/crates/evm-coder/procedural/Cargo.toml
@@ -8,9 +8,12 @@
proc-macro = true
[dependencies]
+# Ethereum uses keccak (=sha3) for selectors
sha3 = "0.10.1"
+# Value formatting
+hex = "0.4.3"
+Inflector = "0.11.4"
+# General proc-macro utilities
quote = "1.0"
proc-macro2 = "1.0"
syn = { version = "1.0", features = ["full"] }
-hex = "0.4.3"
-Inflector = "0.11.4"
crates/evm-coder/procedural/src/lib.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/lib.rs
+++ b/crates/evm-coder/procedural/src/lib.rs
@@ -21,8 +21,8 @@
use quote::quote;
use sha3::{Digest, Keccak256};
use syn::{
- DeriveInput, GenericArgument, Ident, ItemImpl, Pat, Path, PathArguments,
- PathSegment, Type, parse_macro_input, spanned::Spanned,
+ DeriveInput, GenericArgument, Ident, ItemImpl, Pat, Path, PathArguments, PathSegment, Type,
+ parse_macro_input, spanned::Spanned,
};
mod solidity_interface;
@@ -199,58 +199,7 @@
Ident::new(&name, ident.span())
}
-/// Derives call enum implementing [`evm_coder::Callable`], [`evm_coder::Weighted`]
-/// and [`evm_coder::Call`] from impl block
-///
-/// ## Macro syntax
-///
-/// `#[solidity_interface(name, is, inline_is, events)]`
-/// - *name*: used in generated code, and for Call enum name
-/// - *is*: used to provide call inheritance, not found methods will be delegated to all contracts
-/// specified in is/inline_is
-/// - *inline_is*: same as is, but selectors for passed contracts will be used by derived ERC165
-/// implementation
-///
-/// `#[weight(value)]`
-/// Can be added to every method of impl block, used for deriving [`evm_coder::Weighted`], which
-/// is used by substrate bridge
-/// - *value*: expression, which evaluates to weight required to call this method.
-/// This expression can use call arguments to calculate non-constant execution time.
-/// This expression should evaluate faster than actual execution does, and may provide worser case
-/// than one is called
-///
-/// `#[solidity_interface(rename_selector)]`
-/// - *rename_selector*: by default, selector name will be generated by transforming method name
-/// from snake_case to camelCase. Use this option, if other naming convention is required.
-/// I.e: method `token_uri` will be automatically renamed to `tokenUri` in selector, but name
-/// required by ERC721 standard is `tokenURI`, thus we need to specify `rename_selector = "tokenURI"`
-/// explicitly
-///
-/// Also, any contract method may have doc comments, which will be automatically added to generated
-/// solidity interface definitions
-///
-/// ## Example
-///
-/// ```ignore
-/// struct SuperContract;
-/// struct InlineContract;
-/// struct Contract;
-///
-/// #[derive(ToLog)]
-/// enum ContractEvents {
-/// Event(#[indexed] uint32),
-/// }
-///
-/// #[solidity_interface(name = MyContract, is(SuperContract), inline_is(InlineContract))]
-/// impl Contract {
-/// /// Multiply two numbers
-/// #[weight(200 + a + b)]
-/// #[solidity_interface(rename_selector = "mul")]
-/// fn mul(&mut self, a: uint32, b: uint32) -> Result<uint32> {
-/// Ok(a.checked_mul(b).ok_or("overflow")?)
-/// }
-/// }
-/// ```
+/// See documentation for this proc-macro reexported in `evm-coder` crate
#[proc_macro_attribute]
pub fn solidity_interface(args: TokenStream, stream: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as solidity_interface::InterfaceInfo);
@@ -282,10 +231,7 @@
stream
}
-/// ## Syntax
-///
-/// `#[indexed]`
-/// Marks this field as indexed, so it will appear in [`ethereum::Log`] topics instead of data
+/// See documentation for this proc-macro reexported in `evm-coder` crate
#[proc_macro_derive(ToLog, attributes(indexed))]
pub fn to_log(value: TokenStream) -> TokenStream {
let input = parse_macro_input!(value as DeriveInput);
crates/evm-coder/src/abi.rsdiffbeforeafterboth--- a/crates/evm-coder/src/abi.rs
+++ b/crates/evm-coder/src/abi.rs
@@ -14,8 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-//! TODO: I misunterstood therminology, abi IS rlp encoded, so
-//! this module should be replaced with rlp crate
+//! Implementation of EVM RLP reader/writer
#![allow(dead_code)]
@@ -32,6 +31,7 @@
const ABI_ALIGNMENT: usize = 32;
+/// View into RLP data, which provides method to read typed items from it
#[derive(Clone)]
pub struct AbiReader<'i> {
buf: &'i [u8],
@@ -39,6 +39,7 @@
offset: usize,
}
impl<'i> AbiReader<'i> {
+ /// Start reading RLP buffer, assuming there is no padding bytes
pub fn new(buf: &'i [u8]) -> Self {
Self {
buf,
@@ -46,6 +47,7 @@
offset: 0,
}
}
+ /// Start reading RLP buffer, parsing first 4 bytes as selector
pub fn new_call(buf: &'i [u8]) -> Result<(types::bytes4, Self)> {
if buf.len() < 4 {
return Err(Error::Error(ExitError::OutOfOffset));
@@ -109,10 +111,12 @@
)
}
+ /// Read [`H160`] at current position, then advance
pub fn address(&mut self) -> Result<H160> {
Ok(H160(self.read_padleft()?))
}
+ /// Read [`bool`] at current position, then advance
pub fn bool(&mut self) -> Result<bool> {
let data: [u8; 1] = self.read_padleft()?;
match data[0] {
@@ -122,49 +126,61 @@
}
}
+ /// Read [`[u8; 4]`] at current position, then advance
pub fn bytes4(&mut self) -> Result<[u8; 4]> {
self.read_padright()
}
+ /// Read [`Vec<u8>`] at current position, then advance
pub fn bytes(&mut self) -> Result<Vec<u8>> {
let mut subresult = self.subresult()?;
- let length = subresult.read_usize()?;
+ let length = subresult.uint32()? as usize;
if subresult.buf.len() < subresult.offset + length {
return Err(Error::Error(ExitError::OutOfOffset));
}
Ok(subresult.buf[subresult.offset..subresult.offset + length].into())
}
+
+ /// Read [`string`] at current position, then advance
pub fn string(&mut self) -> Result<string> {
string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))
}
+ /// Read [`u8`] at current position, then advance
pub fn uint8(&mut self) -> Result<u8> {
Ok(self.read_padleft::<1>()?[0])
}
+ /// Read [`u32`] at current position, then advance
pub fn uint32(&mut self) -> Result<u32> {
Ok(u32::from_be_bytes(self.read_padleft()?))
}
+ /// Read [`u128`] at current position, then advance
pub fn uint128(&mut self) -> Result<u128> {
Ok(u128::from_be_bytes(self.read_padleft()?))
}
+ /// Read [`U256`] at current position, then advance
pub fn uint256(&mut self) -> Result<U256> {
let buf: [u8; 32] = self.read_padleft()?;
Ok(U256::from_big_endian(&buf))
}
+ /// Read [`u64`] at current position, then advance
pub fn uint64(&mut self) -> Result<u64> {
Ok(u64::from_be_bytes(self.read_padleft()?))
}
+ /// Read [`usize`] at current position, then advance
+ #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]
pub fn read_usize(&mut self) -> Result<usize> {
Ok(usize::from_be_bytes(self.read_padleft()?))
}
+ /// Slice recursive buffer, advance one word for buffer offset
fn subresult(&mut self) -> Result<AbiReader<'i>> {
- let offset = self.read_usize()?;
+ let offset = self.uint32()? as usize;
if offset + self.subresult_offset > self.buf.len() {
return Err(Error::Error(ExitError::InvalidRange));
}
@@ -175,11 +191,13 @@
})
}
+ /// Is this parser reached end of buffer?
pub fn is_finished(&self) -> bool {
self.buf.len() == self.offset
}
}
+/// Writer for RLP encoded data
#[derive(Default)]
pub struct AbiWriter {
static_part: Vec<u8>,
@@ -187,9 +205,11 @@
had_call: bool,
}
impl AbiWriter {
+ /// Initialize internal buffers for output data, assuming no padding required
pub fn new() -> Self {
Self::default()
}
+ /// Initialize internal buffers, inserting method selector at beginning
pub fn new_call(method_id: u32) -> Self {
let mut val = Self::new();
val.static_part.extend(&method_id.to_be_bytes());
@@ -211,59 +231,71 @@
.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]);
}
+ /// Write [`H160`] to end of buffer
pub fn address(&mut self, address: &H160) {
self.write_padleft(&address.0)
}
+ /// Write [`bool`] to end of buffer
pub fn bool(&mut self, value: &bool) {
self.write_padleft(&[if *value { 1 } else { 0 }])
}
+ /// Write [`u8`] to end of buffer
pub fn uint8(&mut self, value: &u8) {
self.write_padleft(&[*value])
}
+ /// Write [`u32`] to end of buffer
pub fn uint32(&mut self, value: &u32) {
self.write_padleft(&u32::to_be_bytes(*value))
}
+ /// Write [`u128`] to end of buffer
pub fn uint128(&mut self, value: &u128) {
self.write_padleft(&u128::to_be_bytes(*value))
}
+ /// Write [`U256`] to end of buffer
pub fn uint256(&mut self, value: &U256) {
let mut out = [0; 32];
value.to_big_endian(&mut out);
self.write_padleft(&out)
}
+ /// Write [`usize`] to end of buffer
+ #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]
pub fn write_usize(&mut self, value: &usize) {
self.write_padleft(&usize::to_be_bytes(*value))
}
+ /// Append recursive data, writing pending offset at end of buffer
pub fn write_subresult(&mut self, result: Self) {
self.dynamic_part.push((self.static_part.len(), result));
// Empty block, to be filled later
self.write_padleft(&[]);
}
- pub fn memory(&mut self, value: &[u8]) {
+ fn memory(&mut self, value: &[u8]) {
let mut sub = Self::new();
- sub.write_usize(&value.len());
+ sub.uint32(&(value.len() as u32));
for chunk in value.chunks(ABI_ALIGNMENT) {
sub.write_padright(chunk);
}
self.write_subresult(sub);
}
+ /// Append recursive [`str`] at end of buffer
pub fn string(&mut self, value: &str) {
self.memory(value.as_bytes())
}
+ /// Append recursive [`[u8]`] at end of buffer
pub fn bytes(&mut self, value: &[u8]) {
self.memory(value)
}
+ /// Finish writer, concatenating all internal buffers
pub fn finish(mut self) -> Vec<u8> {
for (static_offset, part) in self.dynamic_part {
let part_offset = self.static_part.len() - self.had_call.then(|| 4).unwrap_or(0);
@@ -278,7 +310,13 @@
}
}
+/// [`AbiReader`] implements reading of many types, but it should
+/// be limited to types defined in spec
+///
+/// As this trait can't be made sealed,
+/// instead of having `impl AbiRead for T`, we have `impl AbiRead<T> for AbiReader`
pub trait AbiRead<T> {
+ /// Read item from current position, advanding decoder
fn abi_read(&mut self) -> Result<T>;
}
@@ -318,7 +356,7 @@
{
fn abi_read(&mut self) -> Result<Vec<R>> {
let mut sub = self.subresult()?;
- let size = sub.read_usize()?;
+ let size = sub.uint32()? as usize;
sub.subresult_offset = sub.offset;
let mut out = Vec::with_capacity(size);
for _ in 0..size {
@@ -366,8 +404,13 @@
impl_tuples! {A B C D E F G H I}
impl_tuples! {A B C D E F G H I J}
+/// For questions about inability to provide custom implementations,
+/// see [`AbiRead`]
pub trait AbiWrite {
+ /// Write value to end of specified encoder
fn abi_write(&self, writer: &mut AbiWriter);
+ /// Specialization for [`crate::solidity_interface`] implementation,
+ /// see comment in `impl AbiWrite for ResultWithPostInfo`
fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {
let mut writer = AbiWriter::new();
self.abi_write(&mut writer);
@@ -375,13 +418,11 @@
}
}
+/// This particular AbiWrite implementation should be split to another trait,
+/// which only implements `to_result`, but due to lack of specialization feature
+/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,
+/// so here we abusing default trait methods for it
impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {
- // this particular AbiWrite implementation should be split to another trait,
- // which only implements [`to_result`]
- //
- // But due to lack of specialization feature in stable Rust, we can't have
- // blanket impl of this trait `for T where T: AbiWrite`, so here we abusing
- // default trait methods for it
fn abi_write(&self, _writer: &mut AbiWriter) {
debug_assert!(false, "shouldn't be called, see comment")
}
@@ -432,6 +473,8 @@
fn abi_write(&self, _writer: &mut AbiWriter) {}
}
+/// Helper macros to parse reader into variables
+#[deprecated]
#[macro_export]
macro_rules! abi_decode {
($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {
@@ -440,6 +483,9 @@
)+
}
}
+
+/// Helper macros to construct RLP-encoded buffer
+#[deprecated]
#[macro_export]
macro_rules! abi_encode {
($($typ:ident($value:expr)),* $(,)?) => {{
crates/evm-coder/src/events.rsdiffbeforeafterboth--- a/crates/evm-coder/src/events.rs
+++ b/crates/evm-coder/src/events.rs
@@ -19,11 +19,23 @@
use crate::types::*;
+/// Implementation of this trait should not be written manually,
+/// instead use [`crate::ToLog`] proc macros.
+///
+/// See also [`evm_coder_procedural::ToLog`], [solidity docs on events](https://docs.soliditylang.org/en/develop/contracts.html#events)
pub trait ToLog {
+ /// Convert event to [`ethereum::Log`].
+ /// Because event by itself doesn't contains current contract
+ /// address, it should be specified manually.
fn to_log(&self, contract: H160) -> Log;
}
+/// Only items implementing `ToTopic` may be used as `#[indexed]` field
+/// in [`crate::ToLog`] macro usage.
+///
+/// See also (solidity docs on events)[<https://docs.soliditylang.org/en/develop/contracts.html#events>]
pub trait ToTopic {
+ /// Convert value to topic to be used in [`ethereum::Log`]
fn to_topic(&self) -> H256;
}
crates/evm-coder/src/execution.rsdiffbeforeafterboth--- a/crates/evm-coder/src/execution.rs
+++ b/crates/evm-coder/src/execution.rs
@@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+//! Contract execution related types
+
#[cfg(not(feature = "std"))]
use alloc::string::{String, ToString};
use evm_core::{ExitError, ExitFatal};
@@ -22,10 +24,14 @@
use crate::Weight;
+/// Execution error, should be convertible between EVM and Substrate.
#[derive(Debug, Clone)]
pub enum Error {
+ /// Non-fatal contract error occured
Revert(String),
+ /// EVM fatal error
Fatal(ExitFatal),
+ /// EVM normal error
Error(ExitError),
}
@@ -38,9 +44,12 @@
}
}
+/// To be used in [`crate::solidity_interface`] implementation.
pub type Result<T> = core::result::Result<T, Error>;
+/// Static information collected from [`crate::weight`].
pub struct DispatchInfo {
+ /// Statically predicted call weight
pub weight: Weight,
}
@@ -55,16 +64,22 @@
}
}
+/// Weight information that is only available post dispatch.
+/// Note: This can only be used to reduce the weight or fee, not increase it.
#[derive(Default, Clone)]
pub struct PostDispatchInfo {
+ /// Actual weight consumed by call
actual_weight: Option<Weight>,
}
impl PostDispatchInfo {
+ /// Calculate amount to be returned back to user
pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight {
info.weight - self.calc_actual_weight(info)
}
+ /// Calculate actual cansumed weight, saturating to weight reported
+ /// pre-dispatch
pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight {
if let Some(actual_weight) = self.actual_weight {
actual_weight.min(info.weight)
@@ -74,9 +89,12 @@
}
}
+/// Wrapper for PostDispatchInfo and any user-provided data
#[derive(Clone)]
pub struct WithPostDispatchInfo<T> {
+ /// User provided data
pub data: T,
+ /// Info known after dispatch
pub post_info: PostDispatchInfo,
}
@@ -89,5 +107,6 @@
}
}
+/// Return type of items in [`crate::solidity_interface`] definition
pub type ResultWithPostInfo<T> =
core::result::Result<WithPostDispatchInfo<T>, WithPostDispatchInfo<Error>>;
crates/evm-coder/src/lib.rsdiffbeforeafterboth--- a/crates/evm-coder/src/lib.rs
+++ b/crates/evm-coder/src/lib.rs
@@ -14,22 +14,102 @@
// You should have received a copy of the GNU General Public License
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+#![doc = include_str!("../README.md")]
+#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(not(feature = "std"))]
extern crate alloc;
use abi::{AbiRead, AbiReader, AbiWriter};
-pub use evm_coder_macros::{event_topic, fn_selector, solidity_interface, solidity, weight, ToLog};
+pub use evm_coder_procedural::{event_topic, fn_selector};
pub mod abi;
-pub mod events;
-pub use events::ToLog;
+pub use events::{ToLog, ToTopic};
use execution::DispatchInfo;
pub mod execution;
+
+/// Derives call enum implementing [`crate::Callable`], [`crate::Weighted`]
+/// and [`crate::Call`] from impl block.
+///
+/// ## Macro syntax
+///
+/// `#[solidity_interface(name, is, inline_is, events)]`
+/// - *name* - used in generated code, and for Call enum name
+/// - *is* - used to provide call inheritance, not found methods will be delegated to all contracts
+/// specified in is/inline_is
+/// - *inline_is* - same as is, but selectors for passed contracts will be used by derived ERC165
+/// implementation
+///
+/// `#[weight(value)]`
+/// Can be added to every method of impl block, used for deriving [`crate::Weighted`], which
+/// is used by substrate bridge.
+/// - *value*: expression, which evaluates to weight required to call this method.
+/// This expression can use call arguments to calculate non-constant execution time.
+/// This expression should evaluate faster than actual execution does, and may provide worser case
+/// than one is called.
+///
+/// `#[solidity_interface(rename_selector)]`
+/// - *rename_selector* - by default, selector name will be generated by transforming method name
+/// from snake_case to camelCase. Use this option, if other naming convention is required.
+/// I.e: method `token_uri` will be automatically renamed to `tokenUri` in selector, but name
+/// required by ERC721 standard is `tokenURI`, thus we need to specify `rename_selector = "tokenURI"`
+/// explicitly.
+///
+/// Both contract and contract methods may have doccomments, which will end up in a generated
+/// solidity interface file, thus you should use [solidity syntax](https://docs.soliditylang.org/en/latest/natspec-format.html) for writing documentation in this macro
+///
+/// ## Example
+///
+/// ```ignore
+/// struct SuperContract;
+/// struct InlineContract;
+/// struct Contract;
+///
+/// #[derive(ToLog)]
+/// enum ContractEvents {
+/// Event(#[indexed] uint32),
+/// }
+///
+/// /// @dev This contract provides function to multiply two numbers
+/// #[solidity_interface(name = MyContract, is(SuperContract), inline_is(InlineContract))]
+/// impl Contract {
+/// /// Multiply two numbers
+/// /// @param a First number
+/// /// @param b Second number
+/// /// @return uint32 Product of two passed numbers
+/// /// @dev This function returns error in case of overflow
+/// #[weight(200 + a + b)]
+/// #[solidity_interface(rename_selector = "mul")]
+/// fn mul(&mut self, a: uint32, b: uint32) -> Result<uint32> {
+/// Ok(a.checked_mul(b).ok_or("overflow")?)
+/// }
+/// }
+/// ```
+pub use evm_coder_procedural::solidity_interface;
+/// See [`solidity_interface`]
+pub use evm_coder_procedural::solidity;
+/// See [`solidity_interface`]
+pub use evm_coder_procedural::weight;
+
+/// Derives [`ToLog`] for enum
+///
+/// Selectors will be derived from variant names, there is currently no way to have custom naming
+/// for them
+///
+/// `#[indexed]`
+/// Marks this field as indexed, so it will appear in [`ethereum::Log`] topics instead of data
+pub use evm_coder_procedural::ToLog;
+
+// Api of those modules shouldn't be consumed directly, it is only exported for usage in proc macros
+#[doc(hidden)]
+pub mod events;
+#[doc(hidden)]
pub mod solidity;
-/// Solidity type definitions
+/// Solidity type definitions (aliases from solidity name to rust type)
+/// To be used in [`solidity_interface`] definitions, to make sure there is no
+/// type conflict between Rust code and generated definitions
pub mod types {
- #![allow(non_camel_case_types)]
+ #![allow(non_camel_case_types, missing_docs)]
#[cfg(not(feature = "std"))]
use alloc::{vec::Vec};
@@ -54,6 +134,8 @@
pub type string = ::std::string::String;
pub type bytes = Vec<u8>;
+ /// Solidity doesn't have `void` type, however we have special implementation
+ /// for empty tuple return type
pub type void = ();
//#region Special types
@@ -63,36 +145,64 @@
pub type caller = address;
//#endregion
+ /// Ethereum typed call message, similar to solidity
+ /// `msg` object.
pub struct Msg<C> {
pub call: C,
+ /// Address of user, which called this contract.
pub caller: H160,
+ /// Payment amount to contract.
+ /// Contract should reject payment, if target call is not payable,
+ /// and there is no `receiver()` function defined.
pub value: U256,
}
}
+/// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macro
pub trait Call: Sized {
+ /// Parse call buffer into typed call enum
fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>>;
}
+/// Intended to be used as `#[weight]` output type
+/// Should be same between evm-coder and substrate to avoid confusion
+///
+/// Isn't same thing as gas, some mapping is required between those types
pub type Weight = u64;
+/// In substrate, we have benchmarking, which allows
+/// us to not rely on gas metering, but instead predict amount of gas to execute call
pub trait Weighted: Call {
+ /// Predict weight of this call
fn weight(&self) -> DispatchInfo;
}
+/// Type callable with ethereum message, may be implemented by [`solidity_interface`] macro
+/// on interface implementation, or for externally-owned real EVM contract
pub trait Callable<C: Call> {
+ /// Call contract using specified call data
fn call(&mut self, call: types::Msg<C>) -> execution::ResultWithPostInfo<AbiWriter>;
}
-/// Implementation is implicitly provided for all interfaces
+/// Implementation of ERC165 is implicitly generated for all interfaces in [`solidity_interface`],
+/// this structure holds parsed data for ERC165Call subvariant
+///
+/// Note: no [`Callable`] implementation is provided, call implementation is inlined into every
+/// implementing contract
///
-/// Note: no Callable implementation is provided
+/// See <https://eips.ethereum.org/EIPS/eip-165>
#[derive(Debug)]
pub enum ERC165Call {
- SupportsInterface { interface_id: types::bytes4 },
+ /// ERC165 provides single method, which returns true, if contract
+ /// implements specified interface
+ SupportsInterface {
+ /// Requested interface
+ interface_id: types::bytes4,
+ },
}
impl ERC165Call {
+ /// ERC165 selector is provided by standard
pub const INTERFACE_ID: types::bytes4 = u32::to_be_bytes(0x01ffc9a7);
}
crates/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