1234567891011121314151617#![doc = include_str!("../README.md")]18#![deny(missing_docs)]19#![macro_use]20#![cfg_attr(not(feature = "std"), no_std)]21#[cfg(not(feature = "std"))]22extern crate alloc;2324use abi::{AbiRead, AbiReader, AbiWriter};25pub use evm_coder_procedural::{event_topic, fn_selector};26pub mod abi;27pub use events::{ToLog, ToTopic};28use execution::DispatchInfo;29pub mod execution;30#[macro_use]31pub mod custom_signature;323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091pub use evm_coder_procedural::solidity_interface;9293pub use evm_coder_procedural::solidity;9495pub use evm_coder_procedural::weight;96pub use sha3_const;979899100101102103104105pub use evm_coder_procedural::ToLog;106107108#[doc(hidden)]109pub mod events;110#[doc(hidden)]111#[cfg(feature = "stubgen")]112pub mod solidity;113114115116117pub mod types {118 #![allow(non_camel_case_types, missing_docs)]119120 #[cfg(not(feature = "std"))]121 use alloc::{vec::Vec};122 use pallet_evm::account::CrossAccountId;123 use primitive_types::{U256, H160, H256};124 use core::str::from_utf8;125126 use crate::custom_signature::SignatureUnit;127128 pub trait Signature {129 const SIGNATURE: SignatureUnit;130131 fn as_str() -> &'static str {132 from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8")133 }134 }135136 impl Signature for bool {137 const SIGNATURE: SignatureUnit = make_signature!(new fixed("bool"));138 }139140 macro_rules! define_simple_type {141 (type $ident:ident = $ty:ty) => {142 pub type $ident = $ty;143 impl Signature for $ty {144 const SIGNATURE: SignatureUnit = make_signature!(new fixed(stringify!($ident)));145 }146 };147 }148149 define_simple_type!(type address = H160);150151 define_simple_type!(type uint8 = u8);152 define_simple_type!(type uint16 = u16);153 define_simple_type!(type uint32 = u32);154 define_simple_type!(type uint64 = u64);155 define_simple_type!(type uint128 = u128);156 define_simple_type!(type uint256 = U256);157 define_simple_type!(type bytes4 = [u8; 4]);158159 define_simple_type!(type topic = H256);160161 #[cfg(not(feature = "std"))]162 define_simple_type!(type string = ::alloc::string::String);163 #[cfg(feature = "std")]164 define_simple_type!(type string = ::std::string::String);165166 #[derive(Default, Debug, PartialEq)]167 pub struct bytes(pub Vec<u8>);168 impl Signature for bytes {169 const SIGNATURE: SignatureUnit = make_signature!(new fixed("bytes"));170 }171172 173 174 pub type void = ();175176 177 178 pub type value = U256;179 180 pub type caller = address;181 182183 184 185 pub struct Msg<C> {186 pub call: C,187 188 pub caller: H160,189 190 191 192 pub value: U256,193 }194195 impl From<Vec<u8>> for bytes {196 fn from(src: Vec<u8>) -> Self {197 Self(src)198 }199 }200201 #[allow(clippy::from_over_into)]202 impl Into<Vec<u8>> for bytes {203 fn into(self) -> Vec<u8> {204 self.0205 }206 }207208 impl bytes {209 #[must_use]210 pub fn len(&self) -> usize {211 self.0.len()212 }213214 #[must_use]215 pub fn is_empty(&self) -> bool {216 self.len() == 0217 }218 }219220 #[derive(Debug, Default)]221 pub struct EthCrossAccount {222 pub(crate) eth: address,223 pub(crate) sub: uint256,224 }225226 impl EthCrossAccount {227 pub fn from_sub_cross_account<T>(cross_account_id: &T::CrossAccountId) -> Self228 where229 T: pallet_evm::account::Config,230 T::AccountId: AsRef<[u8; 32]>,231 {232 if cross_account_id.is_canonical_substrate() {233 Self {234 eth: Default::default(),235 sub: convert_cross_account_to_uint256::<T>(cross_account_id),236 }237 } else {238 Self {239 eth: *cross_account_id.as_eth(),240 sub: Default::default(),241 }242 }243 }244245 pub fn into_sub_cross_account<T>(&self) -> crate::execution::Result<T::CrossAccountId>246 where247 T: pallet_evm::account::Config,248 T::AccountId: From<[u8; 32]>,249 {250 if self.eth == Default::default() && self.sub == Default::default() {251 Err("All fields of cross account is zeroed".into())252 } else if self.eth == Default::default() {253 Ok(convert_uint256_to_cross_account::<T>(self.sub))254 } else if self.sub == Default::default() {255 Ok(T::CrossAccountId::from_eth(self.eth))256 } else {257 Err("All fields of cross account is non zeroed".into())258 }259 }260 }261262 impl Signature for EthCrossAccount {263 const SIGNATURE: SignatureUnit = make_signature!(new fixed("(address,uint256)"));264 }265266 267 pub fn convert_cross_account_to_uint256<T: pallet_evm::account::Config>(268 from: &T::CrossAccountId,269 ) -> uint256270 where271 T::AccountId: AsRef<[u8; 32]>,272 {273 let slice = from.as_sub().as_ref();274 uint256::from_big_endian(slice)275 }276277 278 pub fn convert_uint256_to_cross_account<T: pallet_evm::account::Config>(279 from: uint256,280 ) -> T::CrossAccountId281 where282 T::AccountId: From<[u8; 32]>,283 {284 let mut new_admin_arr = [0_u8; 32];285 from.to_big_endian(&mut new_admin_arr);286 let account_id = T::AccountId::from(new_admin_arr);287 T::CrossAccountId::from_sub(account_id)288 }289}290291292pub trait Call: Sized {293 294 fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>>;295}296297298299300301pub type Weight = frame_support::weights::Weight;302303304305pub trait Weighted: Call {306 307 fn weight(&self) -> DispatchInfo;308}309310311312pub trait Callable<C: Call> {313 314 fn call(&mut self, call: types::Msg<C>) -> execution::ResultWithPostInfo<AbiWriter>;315}316317318319320321322323324#[derive(Debug)]325pub enum ERC165Call {326 327 328 SupportsInterface {329 330 interface_id: types::bytes4,331 },332}333334impl ERC165Call {335 336 pub const INTERFACE_ID: types::bytes4 = u32::to_be_bytes(0x01ffc9a7);337}338339impl Call for ERC165Call {340 fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>> {341 if selector != Self::INTERFACE_ID {342 return Ok(None);343 }344 Ok(Some(Self::SupportsInterface {345 interface_id: types::bytes4::abi_read(input)?,346 }))347 }348}349350351352353354355#[macro_export]356macro_rules! generate_stubgen {357 ($name:ident, $decl:ty, $is_impl:literal) => {358 #[cfg(feature = "stubgen")]359 #[test]360 #[ignore]361 fn $name() {362 use evm_coder::solidity::TypeCollector;363 let mut out = TypeCollector::new();364 <$decl>::generate_solidity_interface(&mut out, $is_impl);365 println!("=== SNIP START ===");366 println!("// SPDX-License-Identifier: OTHER");367 println!("// This code is automatically generated");368 println!();369 println!("pragma solidity >=0.8.0 <0.9.0;");370 println!();371 for b in out.finish() {372 println!("{}", b);373 }374 println!("=== SNIP END ===");375 }376 };377}378379#[cfg(test)]380mod tests {381 use super::*;382383 #[test]384 fn function_selector_generation() {385 assert_eq!(fn_selector!(transfer(address, uint256)), 0xa9059cbb);386 }387388 #[test]389 fn event_topic_generation() {390 assert_eq!(391 hex::encode(&event_topic!(Transfer(address, address, uint256))[..]),392 "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",393 );394 }395}