difftreelog
feat implement #[weight] macro for evm support
in: master
35 files changed
crates/evm-coder-macros/src/lib.rsdiffbeforeafterboth211pub fn solidity(_args: TokenStream, stream: TokenStream) -> TokenStream {211pub fn solidity(_args: TokenStream, stream: TokenStream) -> TokenStream {212 stream212 stream213}213}214#[proc_macro_attribute]215pub fn weight(_args: TokenStream, stream: TokenStream) -> TokenStream {216 stream217}214218215#[proc_macro_derive(ToLog, attributes(indexed))]219#[proc_macro_derive(ToLog, attributes(indexed))]216pub fn to_log(value: TokenStream) -> TokenStream {220pub fn to_log(value: TokenStream) -> TokenStream {crates/evm-coder-macros/src/solidity_interface.rsdiffbeforeafterboth30 })30 })31 }31 }323233 fn expand_call_def(&self) -> proc_macro2::TokenStream {33 fn expand_call_def(&self, gen_ref: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {34 let name = &self.name;34 let name = &self.name;35 let pascal_call_name = &self.pascal_call_name;35 let pascal_call_name = &self.pascal_call_name;36 quote! {36 quote! {37 #name(#pascal_call_name)37 #name(#pascal_call_name #gen_ref)38 }38 }39 }39 }404046 }46 }474748 fn expand_supports_interface(&self) -> proc_macro2::TokenStream {48 fn expand_supports_interface(49 &self,50 generics: &proc_macro2::TokenStream,51 ) -> proc_macro2::TokenStream {49 let pascal_call_name = &self.pascal_call_name;52 let pascal_call_name = &self.pascal_call_name;50 quote! {53 quote! {51 #pascal_call_name::supports_interface(interface_id)54 <#pascal_call_name #generics>::supports_interface(interface_id)52 }55 }53 }56 }5758 fn expand_variant_weight(&self) -> proc_macro2::TokenStream {59 let name = &self.name;60 quote! {61 Self::#name(call) => call.weight()62 }63 }546455 fn expand_variant_call(&self) -> proc_macro2::TokenStream {65 fn expand_variant_call(66 &self,67 call_name: &proc_macro2::Ident,68 generics: &proc_macro2::TokenStream,69 ) -> proc_macro2::TokenStream {56 let name = &self.name;70 let name = &self.name;57 let pascal_call_name = &self.pascal_call_name;71 let pascal_call_name = &self.pascal_call_name;58 quote! {72 quote! {59 InternalCall::#name(call) => return <Self as ::evm_coder::Callable<#pascal_call_name>>::call(self, Msg {73 #call_name::#name(call) => return <Self as ::evm_coder::Callable<#pascal_call_name #generics>>::call(self, Msg {60 call,74 call,61 caller: c.caller,75 caller: c.caller,62 value: c.value,76 value: c.value,63 })77 })64 }78 }65 }79 }668067 fn expand_parse(&self) -> proc_macro2::TokenStream {81 fn expand_parse(&self, generics: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {68 let name = &self.name;82 let name = &self.name;69 let pascal_call_name = &self.pascal_call_name;83 let pascal_call_name = &self.pascal_call_name;70 quote! {84 quote! {71 if let Some(parsed_call) = #pascal_call_name::parse(method_id, reader)? {85 if let Some(parsed_call) = <#pascal_call_name #generics>::parse(method_id, reader)? {72 return Ok(Some(Self::#name(parsed_call)))86 return Ok(Some(Self::#name(parsed_call)))73 }87 }74 }88 }75 }89 }769077 fn expand_generator(&self) -> proc_macro2::TokenStream {91 fn expand_generator(&self, generics: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {78 let pascal_call_name = &self.pascal_call_name;92 let pascal_call_name = &self.pascal_call_name;79 quote! {93 quote! {80 #pascal_call_name::generate_solidity_interface(tc, is_impl);94 <#pascal_call_name #generics>::generate_solidity_interface(tc, is_impl);81 }95 }82 }96 }8397351 Pure,365 Pure,352}366}367368pub struct WeightAttr(syn::Expr);369370mod keyword {371 syn::custom_keyword!(weight);372}373374impl syn::parse::Parse for WeightAttr {375 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {376 input.parse::<syn::Token![#]>()?;377 let content;378 syn::bracketed!(content in input);379 content.parse::<keyword::weight>()?;380381 let weight_content;382 syn::parenthesized!(weight_content in content);383 Ok(WeightAttr(weight_content.parse::<syn::Expr>()?))384 }385}353386354struct Method {387struct Method {355 name: Ident,388 name: Ident,362 has_normal_args: bool,395 has_normal_args: bool,363 mutability: Mutability,396 mutability: Mutability,364 result: Type,397 result: Type,398 weight: Option<Expr>,365 docs: Vec<String>,399 docs: Vec<String>,366}400}367impl Method {401impl Method {370 rename_selector: None,404 rename_selector: None,371 };405 };372 let mut docs = Vec::new();406 let mut docs = Vec::new();407 let mut weight = None;373 for attr in &value.attrs {408 for attr in &value.attrs {374 let ident = parse_ident_from_path(&attr.path, false)?;409 let ident = parse_ident_from_path(&attr.path, false)?;375 if ident == "solidity" {410 if ident == "solidity" {384 _ => unreachable!(),419 _ => unreachable!(),385 };420 };386 docs.push(value);421 docs.push(value);387 }422 } else if ident == "weight" {423 weight = Some(syn::parse2::<WeightAttr>(attr.to_token_stream())?.0);424 }388 }425 }389 let ident = &value.sig.ident;426 let ident = &value.sig.ident;390 let ident_str = ident.to_string();427 let ident_str = ident.to_string();466 has_normal_args,503 has_normal_args,467 mutability,504 mutability,468 result: result.clone(),505 result: result.clone(),506 weight,469 docs,507 docs,470 })508 })471 }509 }528 }566 }529 }567 }530568531 fn expand_variant_call(&self) -> proc_macro2::TokenStream {569 fn expand_variant_call(&self, call_name: &proc_macro2::Ident) -> proc_macro2::TokenStream {532 let pascal_name = &self.pascal_name;570 let pascal_name = &self.pascal_name;533 let name = &self.name;571 let name = &self.name;534572555 let args = self.args.iter().map(|a| a.expand_call_arg());593 let args = self.args.iter().map(|a| a.expand_call_arg());556594557 quote! {595 quote! {558 InternalCall::#pascal_name #matcher => {596 #call_name::#pascal_name #matcher => {559 let result = #receiver #name(597 let result = #receiver #name(560 #(598 #(561 #args,599 #args,562 )*600 )*563 )?;601 )?;564 (&result).abi_write(&mut writer);602 (&result).into_result()565 }603 }566 }604 }567 }605 }606607 fn expand_variant_weight(&self) -> proc_macro2::TokenStream {608 let pascal_name = &self.pascal_name;609 if let Some(weight) = &self.weight {610 let matcher = if self.has_normal_args {611 let names = self612 .args613 .iter()614 .filter(|a| !a.is_special())615 .map(|a| &a.name);616617 quote! {{618 #(619 #names,620 )*621 }}622 } else {623 quote! {}624 };625 quote! {626 Self::#pascal_name #matcher => (#weight).into()627 }628 } else {629 let matcher = if self.has_normal_args {630 quote! {{..}}631 } else {632 quote! {}633 };634 quote! {635 Self::#pascal_name #matcher => ().into()636 }637 }638 }568639569 fn expand_solidity_function(&self) -> proc_macro2::TokenStream {640 fn expand_solidity_function(&self) -> proc_macro2::TokenStream {570 let camel_name = &self.camel_name;641 let camel_name = &self.camel_name;600 }671 }601}672}673674fn generics_list(gen: &Generics) -> proc_macro2::TokenStream {675 if gen.params.is_empty() {676 return quote! {};677 }678 let params = gen.params.iter().map(|p| match p {679 syn::GenericParam::Type(id) => {680 let v = &id.ident;681 quote! {#v}682 }683 syn::GenericParam::Lifetime(lt) => {684 let v = <.lifetime;685 quote! {#v}686 }687 syn::GenericParam::Const(c) => {688 let i = &c.ident;689 quote! {#i}690 }691 });692 quote! { #(#params),* }693}694fn generics_reference(gen: &Generics) -> proc_macro2::TokenStream {695 if gen.params.is_empty() {696 return quote! {};697 }698 let list = generics_list(gen);699 quote! { <#list> }700}701fn generics_data(gen: &Generics) -> proc_macro2::TokenStream {702 let list = generics_list(gen);703 if gen.params.len() == 1 {704 quote! {#list}705 } else {706 quote! { (#list) }707 }708}602709603pub struct SolidityInterface {710pub struct SolidityInterface {604 generics: Generics,711 generics: Generics,628 let solidity_name = self.info.name.to_string();735 let solidity_name = self.info.name.to_string();629 let call_name = pascal_ident_to_call(&self.info.name);736 let call_name = pascal_ident_to_call(&self.info.name);630 let generics = self.generics;737 let generics = self.generics;738 let gen_ref = generics_reference(&generics);739 let gen_data = generics_data(&generics);631740632 let call_sub = self741 let call_sub = self633 .info742 .info634 .inline_is743 .inline_is635 .0744 .0636 .iter()745 .iter()637 .chain(self.info.is.0.iter())746 .chain(self.info.is.0.iter())638 .map(Is::expand_call_def);747 .map(|c| Is::expand_call_def(c, &gen_ref));639 let call_parse = self748 let call_parse = self640 .info749 .info641 .inline_is750 .inline_is642 .0751 .0643 .iter()752 .iter()644 .chain(self.info.is.0.iter())753 .chain(self.info.is.0.iter())645 .map(Is::expand_parse);754 .map(|is| Is::expand_parse(is, &gen_ref));646 let call_variants = self755 let call_variants = self647 .info756 .info648 .inline_is757 .inline_is649 .0758 .0650 .iter()759 .iter()651 .chain(self.info.is.0.iter())760 .chain(self.info.is.0.iter())652 .map(Is::expand_variant_call);761 .map(|c| Is::expand_variant_call(c, &call_name, &gen_ref));762 let weight_variants = self763 .info764 .inline_is765 .0766 .iter()767 .chain(self.info.is.0.iter())768 .map(Is::expand_variant_weight);653769654 let inline_interface_id = self.info.inline_is.0.iter().map(Is::expand_interface_id);770 let inline_interface_id = self.info.inline_is.0.iter().map(Is::expand_interface_id);655 let supports_interface = self.info.is.0.iter().map(Is::expand_supports_interface);771 let supports_interface = self772 .info773 .is774 .0775 .iter()776 .map(|is| Is::expand_supports_interface(is, &gen_ref));656777657 let calls = self.methods.iter().map(Method::expand_call_def);778 let calls = self.methods.iter().map(Method::expand_call_def);658 let consts = self.methods.iter().map(Method::expand_const);779 let consts = self.methods.iter().map(Method::expand_const);659 let interface_id = self.methods.iter().map(Method::expand_interface_id);780 let interface_id = self.methods.iter().map(Method::expand_interface_id);660 let parsers = self.methods.iter().map(Method::expand_parse);781 let parsers = self.methods.iter().map(Method::expand_parse);661 let call_variants_this = self.methods.iter().map(Method::expand_variant_call);782 let call_variants_this = self783 .methods784 .iter()785 .map(|m| Method::expand_variant_call(m, &call_name));786 let weight_variants_this = self.methods.iter().map(Method::expand_variant_weight);662 let solidity_functions = self.methods.iter().map(Method::expand_solidity_function);787 let solidity_functions = self.methods.iter().map(Method::expand_solidity_function);663788664 // TODO: Inline inline_is789 // TODO: Inline inline_is676 .0801 .0677 .iter()802 .iter()678 .chain(self.info.inline_is.0.iter())803 .chain(self.info.inline_is.0.iter())679 .map(Is::expand_generator);804 .map(|is| Is::expand_generator(is, &gen_ref));680 let solidity_event_generators = self.info.events.0.iter().map(Is::expand_event_generator);805 let solidity_event_generators = self.info.events.0.iter().map(Is::expand_event_generator);681806682 // let methods = self.methods.iter().map(Method::solidity_def);807 // let methods = self.methods.iter().map(Method::solidity_def);683808684 quote! {809 quote! {685 #[derive(Debug)]810 #[derive(Debug)]686 pub enum #call_name {811 pub enum #call_name #gen_ref {687 ERC165Call(::evm_coder::ERC165Call),812 ERC165Call(::evm_coder::ERC165Call, ::core::marker::PhantomData<#gen_data>),688 #(813 #(689 #calls,814 #calls,690 )*815 )*691 #(816 #(692 #call_sub,817 #call_sub,693 )*818 )*694 }819 }695 impl #call_name {820 impl #gen_ref #call_name #gen_ref {696 #(821 #(697 #consts822 #consts698 )*823 )*699 pub const fn interface_id() -> u32 {824 pub fn interface_id() -> u32 {700 let mut interface_id = 0;825 let mut interface_id = 0;701 #(#interface_id)*826 #(#interface_id)*702 #(#inline_interface_id)*827 #(#inline_interface_id)*748 tc.collect(out);873 tc.collect(out);749 }874 }750 }875 }751 impl ::evm_coder::Call for #call_name {876 impl #gen_ref ::evm_coder::Call for #call_name #gen_ref {752 fn parse(method_id: u32, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {877 fn parse(method_id: u32, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {753 use ::evm_coder::abi::AbiRead;878 use ::evm_coder::abi::AbiRead;754 match method_id {879 match method_id {755 ::evm_coder::ERC165Call::INTERFACE_ID => return Ok(::evm_coder::ERC165Call::parse(method_id, reader)?.map(Self::ERC165Call)),880 ::evm_coder::ERC165Call::INTERFACE_ID => return Ok(881 ::evm_coder::ERC165Call::parse(method_id, reader)?882 .map(|c| Self::ERC165Call(c, ::core::marker::PhantomData))883 ),756 #(884 #(757 #parsers,885 #parsers,764 return Ok(None);892 return Ok(None);765 }893 }766 }894 }767 impl #generics ::evm_coder::Callable<#call_name> for #name {895 impl #generics ::evm_coder::Weighted for #call_name #gen_ref {896 #[allow(unused_variables)]897 fn weight(&self) -> ::evm_coder::execution::DispatchInfo {898 match self {899 #(900 #weight_variants,901 )*902 // TODO: It should be very cheap, but not free903 Self::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {..}, _) => 100u64.into(),904 #(905 #weight_variants_this,906 )*907 }908 }909 }910 impl #generics ::evm_coder::Callable<#call_name #gen_ref> for #name {768 #[allow(unreachable_code)] // In case of no inner calls911 #[allow(unreachable_code)] // In case of no inner calls769 fn call(&mut self, c: Msg<#call_name>) -> Result<::evm_coder::abi::AbiWriter> {912 fn call(&mut self, c: Msg<#call_name #gen_ref>) -> ::evm_coder::execution::ResultWithPostInfo<::evm_coder::abi::AbiWriter> {770 use ::evm_coder::abi::AbiWrite;913 use ::evm_coder::abi::AbiWrite;771 type InternalCall = #call_name;772 match c.call {914 match c.call {773 #(915 #(774 #call_variants,916 #call_variants,775 )*917 )*776 InternalCall::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {interface_id}) => {918 #call_name::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {interface_id}, _) => {777 let mut writer = ::evm_coder::abi::AbiWriter::default();919 let mut writer = ::evm_coder::abi::AbiWriter::default();778 writer.bool(&InternalCall::supports_interface(interface_id));920 writer.bool(&<#call_name #gen_ref>::supports_interface(interface_id));779 return Ok(writer);921 return Ok(writer.into());780 }922 }781 _ => {},923 _ => {},782 }924 }787 )*929 )*788 _ => unreachable!()930 _ => unreachable!()789 }931 }790 Ok(writer)791 }932 }792 }933 }793 }934 }crates/evm-coder/src/abi.rsdiffbeforeafterboth12use primitive_types::{H160, U256};12use primitive_types::{H160, U256};131314use crate::{execution::Error, types::string};14use crate::{15 execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},16 types::string,17};15use crate::execution::Result;18use crate::execution::Result;1619244}247}245248246impl_abi_readable!(u32, uint32);249impl_abi_readable!(u32, uint32);250impl_abi_readable!(u64, uint64);247impl_abi_readable!(u128, uint128);251impl_abi_readable!(u128, uint128);248impl_abi_readable!(U256, uint256);252impl_abi_readable!(U256, uint256);249impl_abi_readable!(H160, address);253impl_abi_readable!(H160, address);306310307pub trait AbiWrite {311pub trait AbiWrite {308 fn abi_write(&self, writer: &mut AbiWriter);312 fn abi_write(&self, writer: &mut AbiWriter);313 fn into_result(&self) -> ResultWithPostInfo<AbiWriter> {314 let mut writer = AbiWriter::new();315 self.abi_write(&mut writer);316 Ok(writer.into())317 }309}318}319320impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {321 // this particular AbiWrite implementation should be split to another trait,322 // which only implements [`into_result`]323 //324 // But due to lack of specialization feature in stable Rust, we can't have325 // blanket impl of this trait `for T where T: AbiWrite`, so here we abusing326 // default trait methods for it327 fn abi_write(&self, _writer: &mut AbiWriter) {328 debug_assert!(false, "shouldn't be called, see comment")329 }330 fn into_result(&self) -> ResultWithPostInfo<AbiWriter> {331 match self {332 Ok(v) => Ok(WithPostDispatchInfo {333 post_info: v.post_info.clone(),334 data: {335 let mut out = AbiWriter::new();336 v.data.abi_write(&mut out);337 out338 },339 }),340 Err(e) => Err(e.clone()),341 }342 }343}310344311macro_rules! impl_abi_writeable {345macro_rules! impl_abi_writeable {312 ($ty:ty, $method:ident) => {346 ($ty:ty, $method:ident) => {crates/evm-coder/src/execution.rsdiffbeforeafterboth4#[cfg(feature = "std")]4#[cfg(feature = "std")]5use std::string::{String, ToString};5use std::string::{String, ToString};67use crate::Weight;687#[derive(Debug)]9#[derive(Debug, Clone)]8pub enum Error {10pub enum Error {9 Revert(String),11 Revert(String),10 Fatal(ExitFatal),12 Fatal(ExitFatal),222423pub type Result<T> = core::result::Result<T, Error>;25pub type Result<T> = core::result::Result<T, Error>;2627pub struct DispatchInfo {28 pub weight: Weight,29}3031impl From<Weight> for DispatchInfo {32 fn from(weight: Weight) -> Self {33 Self { weight }34 }35}36impl From<()> for DispatchInfo {37 fn from(_: ()) -> Self {38 Self { weight: 0 }39 }40}4142#[derive(Default, Clone)]43pub struct PostDispatchInfo {44 actual_weight: Option<Weight>,45}4647impl PostDispatchInfo {48 pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight {49 info.weight - self.calc_actual_weight(info)50 }5152 pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight {53 if let Some(actual_weight) = self.actual_weight {54 actual_weight.min(info.weight)55 } else {56 info.weight57 }58 }59}6061#[derive(Clone)]62pub struct WithPostDispatchInfo<T> {63 pub data: T,64 pub post_info: PostDispatchInfo,65}6667impl<T> From<T> for WithPostDispatchInfo<T> {68 fn from(data: T) -> Self {69 Self {70 data,71 post_info: Default::default(),72 }73 }74}7576pub type ResultWithPostInfo<T> =77 core::result::Result<WithPostDispatchInfo<T>, WithPostDispatchInfo<Error>>;2478crates/evm-coder/src/lib.rsdiffbeforeafterboth3extern crate alloc;3extern crate alloc;445use abi::{AbiRead, AbiReader, AbiWriter};5use abi::{AbiRead, AbiReader, AbiWriter};6pub use evm_coder_macros::{event_topic, fn_selector, solidity_interface, solidity, ToLog};6pub use evm_coder_macros::{event_topic, fn_selector, solidity_interface, solidity, weight, ToLog};7pub mod abi;7pub mod abi;8pub mod events;8pub mod events;9pub use events::ToLog;9pub use events::ToLog;10use execution::DispatchInfo;10pub mod execution;11pub mod execution;11pub mod solidity;12pub mod solidity;121357 fn parse(selector: u32, input: &mut AbiReader) -> execution::Result<Option<Self>>;58 fn parse(selector: u32, input: &mut AbiReader) -> execution::Result<Option<Self>>;58}59}6061pub type Weight = u64;6263pub trait Weighted: Call {64 fn weight(&self) -> DispatchInfo;65}596660pub trait Callable<C: Call> {67pub trait Callable<C: Call> {61 fn call(&mut self, call: types::Msg<C>) -> execution::Result<AbiWriter>;68 fn call(&mut self, call: types::Msg<C>) -> execution::ResultWithPostInfo<AbiWriter>;62}69}637064/// Implementation is implicitly provided for all interfaces71/// Implementation is implicitly provided for all interfaces84 }91 }85}92}869394/// Generate "tests", which will generate solidity code on execution and print it to stdout95/// Script at .maintain/scripts/generate_api.sh can split this output from test runtime96///97/// This macro receives type usage as second argument, but you can use anything as generics,98/// because no bounds are implied87#[macro_export]99#[macro_export]88macro_rules! generate_stubgen {100macro_rules! generate_stubgen {89 ($name:ident, $decl:ident, $is_impl:literal) => {101 ($name:ident, $decl:ty, $is_impl:literal) => {90 #[test]102 #[test]91 #[ignore]103 #[ignore]92 fn $name() {104 fn $name() {93 use evm_coder::solidity::TypeCollector;105 use evm_coder::solidity::TypeCollector;94 let mut out = TypeCollector::new();106 let mut out = TypeCollector::new();95 $decl::generate_solidity_interface(&mut out, $is_impl);107 <$decl>::generate_solidity_interface(&mut out, $is_impl);96 println!("=== SNIP START ===");108 println!("=== SNIP START ===");97 println!("// SPDX-License-Identifier: OTHER");109 println!("// SPDX-License-Identifier: OTHER");98 println!("// This code is automatically generated");110 println!("// This code is automatically generated");crates/evm-coder/tests/a.rsdiffbeforeafterbothno changes
crates/evm-coder/tests/generics.rsdiffbeforeafterbothno changes
crates/evm-coder/tests/log.rsdiffbeforeafterbothno changes
crates/evm-coder/tests/random.rsdiffbeforeafterbothno changes
crates/evm-coder/tests/solidity_generation.rsdiffbeforeafterbothno changes
node/cli/Cargo.tomldiffbeforeafterboth268jsonrpc-core = '18.0.0'268jsonrpc-core = '18.0.0'269jsonrpc-pubsub = "18.0.0"269jsonrpc-pubsub = "18.0.0"270270271fc-rpc-core = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }271fc-rpc-core = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }272fc-consensus = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }272fc-consensus = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }273fc-mapping-sync = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }273fc-mapping-sync = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }274fc-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }274fc-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }275fc-db = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }275fc-db = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }276fp-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }276fp-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }277pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }277pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }278278279nft-rpc = { path = "../rpc" }279nft-rpc = { path = "../rpc" }280280node/rpc/Cargo.tomldiffbeforeafterboth41substrate-frame-rpc-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }41substrate-frame-rpc-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }42tokio = { version = "0.2.25", features = ["macros", "sync"] }42tokio = { version = "0.2.25", features = ["macros", "sync"] }434344pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }44pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }45fc-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }45fc-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }46fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }46fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }47fc-rpc-core = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }47fc-rpc-core = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }48fc-db = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }48fc-db = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }49fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }49fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }505051pallet-nft = { path = "../../pallets/nft" }51pallet-nft = { path = "../../pallets/nft" }52uc-rpc = { path = "../../client/rpc" }52uc-rpc = { path = "../../client/rpc" }pallets/common/Cargo.tomldiffbeforeafterboth19pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }19pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }20evm-coder = { default-features = false, path = '../../crates/evm-coder' }20evm-coder = { default-features = false, path = '../../crates/evm-coder' }212122pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }22pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }23serde = { version = "1.0.130", default-features = false }23serde = { version = "1.0.130", default-features = false }24scale-info = { version = "1.0.0", default-features = false, features = [24scale-info = { version = "1.0.0", default-features = false, features = [25 "derive",25 "derive",pallets/common/src/lib.rsdiffbeforeafterboth1#![cfg_attr(not(feature = "std"), no_std)]1#![cfg_attr(not(feature = "std"), no_std)]223use core::ops::{Deref, DerefMut};3use core::ops::{Deref, DerefMut};4use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};4use sp_std::vec::Vec;5use sp_std::vec::Vec;5use account::CrossAccountId;6use account::CrossAccountId;6use frame_support::{7use frame_support::{7 dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo},8 dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo},8 ensure, fail,9 ensure, fail,9 traits::{Imbalance, Get, Currency},10 traits::{Imbalance, Get, Currency},10};11};12use pallet_evm::GasWeightMapping;11use nft_data_structs::{13use nft_data_structs::{12 COLLECTION_NUMBER_LIMIT, Collection, CollectionId, CreateItemData, ExistenceRequirement,14 COLLECTION_NUMBER_LIMIT, Collection, CollectionId, CreateItemData, ExistenceRequirement,13 MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_COLLECTION_NAME_LENGTH, MAX_TOKEN_PREFIX_LENGTH,15 MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_COLLECTION_NAME_LENGTH, MAX_TOKEN_PREFIX_LENGTH,27pub struct CollectionHandle<T: Config> {29pub struct CollectionHandle<T: Config> {28 pub id: CollectionId,30 pub id: CollectionId,29 collection: Collection<T>,31 collection: Collection<T>,30 pub recorder: pallet_evm_coder_substrate::SubstrateRecorder<T>,32 pub recorder: SubstrateRecorder<T>,31}33}34impl<T: Config> WithRecorder<T> for CollectionHandle<T> {35 fn recorder(&self) -> &SubstrateRecorder<T> {36 &self.recorder37 }38 fn into_recorder(self) -> SubstrateRecorder<T> {39 self.recorder40 }41}32impl<T: Config> CollectionHandle<T> {42impl<T: Config> CollectionHandle<T> {33 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {43 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {34 <CollectionById<T>>::get(id).map(|collection| Self {44 <CollectionById<T>>::get(id).map(|collection| Self {35 id,45 id,36 collection,46 collection,37 recorder: pallet_evm_coder_substrate::SubstrateRecorder::new(47 recorder: SubstrateRecorder::new(eth::collection_id_to_address(id), gas_limit),38 eth::collection_id_to_address(id),39 gas_limit,40 ),46 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {53 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {47 Ok(Self::new(id).ok_or_else(|| <Error<T>>::CollectionNotFound)?)54 Ok(Self::new(id).ok_or_else(|| <Error<T>>::CollectionNotFound)?)48 }55 }49 pub fn log(&self, log: impl evm_coder::ToLog) -> DispatchResult {56 pub fn log(&self, log: impl evm_coder::ToLog) {50 self.recorder.log_sub(log)57 self.recorder.log(log)51 }58 }52 pub fn log_infallible(&self, log: impl evm_coder::ToLog) {59 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {53 self.recorder.log_infallible(log)54 }55 #[allow(dead_code)]56 fn consume_gas(&self, gas: u64) -> DispatchResult {57 self.recorder.consume_gas_sub(gas)58 }59 pub fn consume_sload(&self) -> DispatchResult {60 self.recorder.consume_sload_sub()60 self.recorder61 .consume_gas(T::GasWeightMapping::weight_to_gas(62 <T as frame_system::Config>::DbWeight::get()63 .read64 .saturating_mul(reads),65 ))61 }66 }62 pub fn consume_sstores(&self, amount: usize) -> DispatchResult {67 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {63 self.recorder.consume_sstores_sub(amount)64 }65 pub fn consume_sstore(&self) -> DispatchResult {66 self.recorder.consume_sstore_sub()67 }68 pub fn consume_log(&self, topics: usize, data: usize) -> DispatchResult {69 self.recorder.consume_log_sub(topics, data)68 self.recorder69 .consume_gas(T::GasWeightMapping::weight_to_gas(70 <T as frame_system::Config>::DbWeight::get()71 .write72 .saturating_mul(writes),73 ))70 }74 }71 pub fn submit_logs(self) -> DispatchResult {75 pub fn submit_logs(self) {72 self.recorder.submit_logs()76 self.recorder.submit_logs()73 }77 }74 pub fn save(self) -> DispatchResult {78 pub fn save(self) -> DispatchResult {75 self.recorder.submit_logs()?;79 self.recorder.submit_logs();76 <CollectionById<T>>::insert(self.id, self.collection);80 <CollectionById<T>>::insert(self.id, self.collection);77 Ok(())81 Ok(())78 }82 }96 ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);100 ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);97 Ok(())101 Ok(())98 }102 }99 pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> Result<bool, DispatchError> {103 pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> bool {100 self.consume_sload()?;101102 Ok(*subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject)))104 *subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject))103 }105 }104 pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult {106 pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult {105 ensure!(self.is_owner_or_admin(subject)?, <Error<T>>::NoPermission);107 ensure!(self.is_owner_or_admin(subject), <Error<T>>::NoPermission);106 Ok(())108 Ok(())107 }109 }108 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> Result<bool, DispatchError> {110 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {109 Ok(self.limits.owner_can_transfer() && self.is_owner_or_admin(user)?)111 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)110 }112 }111 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> Result<bool, DispatchError> {113 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {112 Ok(self.limits.owner_can_transfer() && self.is_owner_or_admin(user)?)114 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)113 }115 }114 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {116 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {115 self.consume_sload()?;116117 ensure!(117 ensure!(118 <Allowlist<T>>::get((self.id, user)),118 <Allowlist<T>>::get((self.id, user)),pallets/evm-coder-substrate/Cargo.tomldiffbeforeafterboth9sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }11sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }10ethereum = { version = "0.9", git = "https://github.com/purestake/ethereum", branch = "joshy-scale-info", default-features = false }12ethereum = { version = "0.9", git = "https://github.com/purestake/ethereum", branch = "joshy-scale-info", default-features = false }11evm-coder = { default-features = false, path = "../../crates/evm-coder" }13evm-coder = { default-features = false, path = "../../crates/evm-coder" }12pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }14pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }13pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }15pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }14frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }16frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }15frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }17frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }18frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }161917[dependencies.codec]20[dependencies.codec]18default-features = false21default-features = false31 "pallet-evm/std",34 "pallet-evm/std",32 "frame-support/std",35 "frame-support/std",33 "frame-system/std",36 "frame-system/std",37 'frame-benchmarking/std',34]38]39runtime-benchmarks = ['frame-benchmarking']3540pallets/evm-coder-substrate/src/benchmarking.rsdiffbeforeafterbothno changes
pallets/evm-coder-substrate/src/lib.rsdiffbeforeafterboth223#[cfg(not(feature = "std"))]3#[cfg(not(feature = "std"))]4extern crate alloc;4extern crate alloc;5// #[cfg(feature = "runtime-benchmarks")]6// pub mod benchmarking;576pub use pallet::*;8pub use pallet::*;7918 };20 };19 use frame_support::{ensure};21 use frame_support::{ensure};20 use pallet_evm::{ExitError, ExitReason, ExitRevert, ExitSucceed, PrecompileOutput};22 use pallet_evm::{23 ExitError, ExitReason, ExitRevert, ExitSucceed, PrecompileOutput, GasWeightMapping,24 };25 use frame_system::ensure_signed;21 pub use frame_support::dispatch::DispatchResult;26 pub use frame_support::dispatch::DispatchResult;22 use pallet_ethereum::EthereumTransactionSender;27 use pallet_ethereum::EthereumTransactionSender;23 use sp_std::cell::RefCell;28 use sp_std::cell::RefCell;24 use sp_std::vec::Vec;29 use sp_std::vec::Vec;25 use sp_core::{H160, H256};30 use sp_core::{H160, H256};26 use ethereum::Log;31 use ethereum::Log;27 use frame_support::{pallet_prelude::*, traits::PalletInfo};32 use frame_support::{pallet_prelude::*, traits::PalletInfo};33 use frame_system::pallet_prelude::*;283429 /// DispatchError is opaque, but we need to somehow extract correct error in case of OutOfGas failure35 /// DispatchError is opaque, but we need to somehow extract correct error in case of OutOfGas failure30 /// So we have this pallet, which defines OutOfGas error, and knews its own id to check if DispatchError36 /// So we have this pallet, which defines OutOfGas error, and knews its own id to check if DispatchError40 #[pallet::config]46 #[pallet::config]41 pub trait Config: frame_system::Config {47 pub trait Config: frame_system::Config {42 type EthereumTransactionSender: pallet_ethereum::EthereumTransactionSender;48 type EthereumTransactionSender: pallet_ethereum::EthereumTransactionSender;49 type GasWeightMapping: pallet_evm::GasWeightMapping;43 }50 }445145 #[pallet::pallet]52 #[pallet::pallet]46 pub struct Pallet<T>(_);53 pub struct Pallet<T>(_);475448 // FIXME: those items are defined as private in evm_gasometer::consts, and we can't directly use it55 #[pallet::call]49 pub const G_LOG: u64 = 375;50 pub const G_LOGDATA: u64 = 8;56 impl<T: Config> Pallet<T> {57 #[pallet::weight(0)]51 pub const G_LOGTOPIC: u64 = 375;58 pub fn empty_call(origin: OriginFor<T>) -> DispatchResult {59 let _sender = ensure_signed(origin)?;60 Ok(())61 }62 }526353 // From instabul hardfork configuration: https://github.com/rust-blockchain/evm/blob/fd4fd6acc0ca3208d6770fdb3ba407c94cdf97c6/runtime/src/lib.rs#L28464 // From instabul hardfork configuration: https://github.com/rust-blockchain/evm/blob/fd4fd6acc0ca3208d6770fdb3ba407c94cdf97c6/runtime/src/lib.rs#L28454 pub const G_SLOAD_WORD: u64 = 800;65 pub const G_SLOAD_WORD: u64 = 800;55 pub const G_SSTORE_WORD: u64 = 20000;66 pub const G_SSTORE_WORD: u64 = 20000;5657 fn log_price(data: usize, topics: usize) -> u64 {58 G_LOG59 .saturating_add((data as u64).saturating_mul(G_LOGDATA))60 .saturating_add((topics as u64).saturating_mul(G_LOGTOPIC))61 }626763 pub fn generate_transaction() -> ethereum::TransactionV0 {68 pub fn generate_transaction() -> ethereum::TransactionV0 {64 use ethereum::{TransactionV0, TransactionAction, TransactionSignature};69 use ethereum::{TransactionV0, TransactionAction, TransactionSignature};98 pub fn is_empty(&self) -> bool {103 pub fn is_empty(&self) -> bool {99 self.logs.borrow().is_empty()104 self.logs.borrow().is_empty()100 }105 }101 pub fn log_sub(&self, log: impl ToLog) -> DispatchResult {106 // TODO: Replace with real storage in pallet-ethereum,102 self.log_raw_sub(log.to_log(self.contract))107 // same way as it is done with frame_system's Events103 }104 pub fn log_raw_sub(&self, log: Log) -> DispatchResult {105 self.consume_gas_sub(log_price(log.data.len(), log.topics.len()))?;106 self.logs.borrow_mut().push(log);107 Ok(())108 }109 /// Doesn't consumes any gas, should be used after consume_log_sub108 /// Doesn't consumes any gas, should be used after consume_log_sub110 pub fn log_infallible(&self, log: impl ToLog) {109 pub fn log(&self, log: impl ToLog) {111 self.logs.borrow_mut().push(log.to_log(self.contract));110 self.logs.borrow_mut().push(log.to_log(self.contract));112 }111 }113 pub fn retrieve_logs(self) -> Vec<Log> {112 pub fn retrieve_logs(self) -> Vec<Log> {126 pub fn consume_sstore_sub(&self) -> DispatchResult {125 pub fn consume_sstore_sub(&self) -> DispatchResult {127 self.consume_gas_sub(G_SSTORE_WORD)126 self.consume_gas_sub(G_SSTORE_WORD)128 }127 }129 pub fn consume_log_sub(&self, topics: usize, data: usize) -> DispatchResult {130 self.consume_gas_sub(log_price(data, topics))131 }132 pub fn consume_gas_sub(&self, gas: u64) -> DispatchResult {128 pub fn consume_gas_sub(&self, gas: u64) -> DispatchResult {133 ensure!(gas != u64::MAX, Error::<T>::OutOfGas);129 ensure!(gas != u64::MAX, Error::<T>::OutOfGas);134 let mut gas_limit = self.gas_limit.borrow_mut();130 let mut gas_limit = self.gas_limit.borrow_mut();154 *gas_limit -= gas;150 *gas_limit -= gas;155 Ok(())151 Ok(())156 }152 }153 pub fn return_gas(&self, gas: u64) {154 let mut gas_limit = self.gas_limit.borrow_mut();155 *gas_limit += gas;156 }157157158 pub fn evm_to_precompile_output(158 pub fn evm_to_precompile_output(159 self,159 self,181 })181 })182 }182 }183183184 pub fn submit_logs(self) -> DispatchResult {184 pub fn submit_logs(self) {185 let logs = self.retrieve_logs();185 let logs = self.retrieve_logs();186 if logs.is_empty() {186 if logs.is_empty() {187 return Ok(());187 return;188 }188 }189 T::EthereumTransactionSender::submit_logs_transaction(generate_transaction(), logs)189 T::EthereumTransactionSender::submit_logs_transaction(190 Default::default(),191 generate_transaction(),192 logs,193 )190 }194 }191 }195 }215 }219 }216 }220 }217221218 pub fn call_internal<C: evm_coder::Call, E: evm_coder::Callable<C>>(222 pub trait WithRecorder<T: Config> {223 fn recorder(&self) -> &SubstrateRecorder<T>;224 fn into_recorder(self) -> SubstrateRecorder<T>;225 }226227 /// Helper to simplify implementing bridge between evm-coder definitions and pallet-evm228 pub fn call<229 T: Config,230 C: evm_coder::Call + evm_coder::Weighted,231 E: evm_coder::Callable<C> + WithRecorder<T>,232 >(233 caller: H160,234 mut e: E,235 value: value,236 input: &[u8],237 ) -> Option<PrecompileOutput> {238 let result = call_internal(caller, &mut e, value, input);239 e.into_recorder().evm_to_precompile_output(result)240 }241242 fn call_internal<243 T: Config,244 C: evm_coder::Call + evm_coder::Weighted,245 E: evm_coder::Callable<C> + WithRecorder<T>,246 >(219 caller: H160,247 caller: H160,220 e: &mut E,248 e: &mut E,228 }256 }229 let call = call.unwrap();257 let call = call.unwrap();258259 let dispatch_info = call.weight();260 e.recorder()261 .consume_gas(T::GasWeightMapping::weight_to_gas(dispatch_info.weight))?;262230 e.call(Msg {263 match e.call(Msg {231 call,264 call,232 caller,265 caller,233 value,266 value,234 })267 }) {268 Ok(v) => {269 let unspent = v.post_info.calc_unspent(&dispatch_info);270 e.recorder()235 .map(Some)271 .return_gas(T::GasWeightMapping::weight_to_gas(unspent));272 Ok(Some(v.data))273 }274 Err(v) => {275 let unspent = v.post_info.calc_unspent(&dispatch_info);276 e.recorder()277 .return_gas(T::GasWeightMapping::weight_to_gas(unspent));278 Err(v.data)279 }280 }236 }281 }237}282}238283pallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth12sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }14sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }13evm-coder = { default-features = false, path = '../../crates/evm-coder' }15evm-coder = { default-features = false, path = '../../crates/evm-coder' }14pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }16pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }15pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }17pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }16up-sponsorship = { default-features = false, path = '../../primitives/sponsorship' }18up-sponsorship = { default-features = false, path = '../../primitives/sponsorship' }17log = "0.4.14"19log = "0.4.14"1820pallets/evm-contract-helpers/exp.rsdiffbeforeafterbothno changes
pallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth1use core::marker::PhantomData;1use core::marker::PhantomData;2use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};2use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};3use pallet_evm_coder_substrate::SubstrateRecorder;3use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};4use pallet_evm::{ExitReason, ExitRevert, OnCreate, OnMethodCall, PrecompileOutput};4use pallet_evm::{ExitReason, ExitRevert, OnCreate, OnMethodCall, PrecompileOutput};5use sp_core::H160;5use sp_core::H160;6use crate::{6use crate::{11use sp_std::{convert::TryInto, vec::Vec};11use sp_std::{convert::TryInto, vec::Vec};121213struct ContractHelpers<T: Config>(SubstrateRecorder<T>);13struct ContractHelpers<T: Config>(SubstrateRecorder<T>);14impl<T: Config> WithRecorder<T> for ContractHelpers<T> {15 fn recorder(&self) -> &SubstrateRecorder<T> {16 &self.017 }1819 fn into_recorder(self) -> SubstrateRecorder<T> {20 self.021 }22}142315#[solidity_interface(name = "ContractHelpers")]24#[solidity_interface(name = "ContractHelpers")]16impl<T: Config> ContractHelpers<T> {25impl<T: Config> ContractHelpers<T> {17 fn contract_owner(&self, contract_address: address) -> Result<address> {26 fn contract_owner(&self, contract_address: address) -> Result<address> {18 self.0.consume_sload()?;19 Ok(<Owner<T>>::get(contract_address))27 Ok(<Owner<T>>::get(contract_address))20 }28 }212922 fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {30 fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {23 self.0.consume_sload()?;24 Ok(<SelfSponsoring<T>>::get(contract_address))31 Ok(<SelfSponsoring<T>>::get(contract_address))25 }32 }263330 contract_address: address,37 contract_address: address,31 enabled: bool,38 enabled: bool,32 ) -> Result<void> {39 ) -> Result<void> {33 self.0.consume_sload()?;34 <Pallet<T>>::ensure_owner(contract_address, caller)?;40 <Pallet<T>>::ensure_owner(contract_address, caller)?;35 self.0.consume_sstore()?;36 <Pallet<T>>::toggle_sponsoring(contract_address, enabled);41 <Pallet<T>>::toggle_sponsoring(contract_address, enabled);37 Ok(())42 Ok(())38 }43 }43 contract_address: address,48 contract_address: address,44 rate_limit: uint32,49 rate_limit: uint32,45 ) -> Result<void> {50 ) -> Result<void> {46 self.0.consume_sload()?;47 <Pallet<T>>::ensure_owner(contract_address, caller)?;51 <Pallet<T>>::ensure_owner(contract_address, caller)?;48 self.0.consume_sstore()?;49 <Pallet<T>>::set_sponsoring_rate_limit(contract_address, rate_limit.into());52 <Pallet<T>>::set_sponsoring_rate_limit(contract_address, rate_limit.into());50 Ok(())53 Ok(())51 }54 }525553 fn get_sponsoring_rate_limit(&self, contract_address: address) -> Result<uint32> {56 fn get_sponsoring_rate_limit(&self, contract_address: address) -> Result<uint32> {54 self.0.consume_sload()?;55 Ok(<SponsoringRateLimit<T>>::get(contract_address)57 Ok(<SponsoringRateLimit<T>>::get(contract_address)56 .try_into()58 .try_into()57 .map_err(|_| "rate limit > u32::MAX")?)59 .map_err(|_| "rate limit > u32::MAX")?)58 }60 }596160 fn allowed(&self, contract_address: address, user: address) -> Result<bool> {62 fn allowed(&self, contract_address: address, user: address) -> Result<bool> {61 self.0.consume_sload()?;62 Ok(<Pallet<T>>::allowed(contract_address, user, true))63 Ok(<Pallet<T>>::allowed(contract_address, user, true))63 }64 }646565 fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {66 fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {66 self.0.consume_sload()?;67 Ok(<AllowlistEnabled<T>>::get(contract_address))67 Ok(<AllowlistEnabled<T>>::get(contract_address))68 }68 }696973 contract_address: address,73 contract_address: address,74 enabled: bool,74 enabled: bool,75 ) -> Result<void> {75 ) -> Result<void> {76 self.0.consume_sload()?;77 <Pallet<T>>::ensure_owner(contract_address, caller)?;76 <Pallet<T>>::ensure_owner(contract_address, caller)?;78 self.0.consume_sstore()?;79 <Pallet<T>>::toggle_allowlist(contract_address, enabled);77 <Pallet<T>>::toggle_allowlist(contract_address, enabled);80 Ok(())78 Ok(())81 }79 }87 user: address,85 user: address,88 allowed: bool,86 allowed: bool,89 ) -> Result<void> {87 ) -> Result<void> {90 self.0.consume_sload()?;91 <Pallet<T>>::ensure_owner(contract_address, caller)?;88 <Pallet<T>>::ensure_owner(contract_address, caller)?;92 self.0.consume_sstore()?;93 <Pallet<T>>::toggle_allowed(contract_address, user, allowed);89 <Pallet<T>>::toggle_allowed(contract_address, user, allowed);94 Ok(())90 Ok(())95 }91 }130 return None;126 return None;131 }127 }132128133 let mut helpers = ContractHelpers::<T>(SubstrateRecorder::<T>::new(*target, gas_left));129 let helpers = ContractHelpers::<T>(SubstrateRecorder::<T>::new(*target, gas_left));134 let result = pallet_evm_coder_substrate::call_internal(*source, &mut helpers, value, input);130 pallet_evm_coder_substrate::call(*source, helpers, value, input)135 helpers.0.evm_to_precompile_output(result)136 }131 }137132138 fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {133 fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {170 }165 }171}166}172167173generate_stubgen!(contract_helpers_impl, ContractHelpersCall, true);168generate_stubgen!(contract_helpers_impl, ContractHelpersCall<()>, true);174generate_stubgen!(contract_helpers_iface, ContractHelpersCall, false);169generate_stubgen!(contract_helpers_iface, ContractHelpersCall<()>, false);175170pallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth21 }21 }22}22}232324// Selector: 31acb1fe24contract ContractHelpers is Dummy, ERC165 {25contract ContractHelpers is Dummy, ERC165 {25 // Selector: contractOwner(address) 5152b14c26 // Selector: contractOwner(address) 5152b14c26 function contractOwner(address contractAddress)27 function contractOwner(address contractAddress)pallets/evm-migration/Cargo.tomldiffbeforeafterboth12sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }14sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }13sp-io = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }15sp-io = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }14sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }16sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }15pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }17pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }16fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }18fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }171918[dependencies.codec]20[dependencies.codec]19default-features = false21default-features = falsepallets/evm-transaction-payment/Cargo.tomldiffbeforeafterboth11sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }13sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }12sp-io = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }14sp-io = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }13sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }15sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }14pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }16pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }15fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }17fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }16pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }18pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }17up-sponsorship = { default-features = false, path = '../../primitives/sponsorship' }19up-sponsorship = { default-features = false, path = '../../primitives/sponsorship' }182019[dependencies.codec]21[dependencies.codec]pallets/fungible/src/erc.rsdiffbeforeafterboth1use core::char::{REPLACEMENT_CHARACTER, decode_utf16};1use core::char::{REPLACEMENT_CHARACTER, decode_utf16};2use core::convert::TryInto;2use core::convert::TryInto;3use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*};3use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};4use nft_data_structs::CollectionMode;4use nft_data_structs::CollectionMode;5use pallet_common::erc::CommonEvmHandler;5use pallet_common::erc::CommonEvmHandler;6use sp_core::{H160, U256};6use sp_core::{H160, U256};7use sp_std::vec::Vec;7use sp_std::vec::Vec;8use pallet_common::account::CrossAccountId;8use pallet_common::account::CrossAccountId;9use pallet_common::erc::PrecompileOutput;9use pallet_common::erc::PrecompileOutput;10use pallet_evm_coder_substrate::{call_internal, dispatch_to_evm};10use pallet_evm_coder_substrate::{call, dispatch_to_evm};111112use crate::{Allowance, Balance, Config, FungibleHandle, Pallet, TotalSupply};12use crate::{13 Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,14 weights::WeightInfo,15};131614#[derive(ToLog)]17#[derive(ToLog)]40 Ok(string::from_utf8_lossy(&self.token_prefix).into())43 Ok(string::from_utf8_lossy(&self.token_prefix).into())41 }44 }42 fn total_supply(&self) -> Result<uint256> {45 fn total_supply(&self) -> Result<uint256> {46 self.consume_store_reads(1)?;43 Ok(<TotalSupply<T>>::get(self.id).into())47 Ok(<TotalSupply<T>>::get(self.id).into())44 }48 }454951 })55 })52 }56 }53 fn balance_of(&self, owner: address) -> Result<uint256> {57 fn balance_of(&self, owner: address) -> Result<uint256> {58 self.consume_store_reads(1)?;54 let owner = T::CrossAccountId::from_eth(owner);59 let owner = T::CrossAccountId::from_eth(owner);55 let balance = <Balance<T>>::get((self.id, owner));60 let balance = <Balance<T>>::get((self.id, owner));56 Ok(balance.into())61 Ok(balance.into())57 }62 }63 #[weight(<SelfWeightOf<T>>::transfer())]58 fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {64 fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {59 let caller = T::CrossAccountId::from_eth(caller);65 let caller = T::CrossAccountId::from_eth(caller);60 let to = T::CrossAccountId::from_eth(to);66 let to = T::CrossAccountId::from_eth(to);63 <Pallet<T>>::transfer(self, &caller, &to, amount).map_err(|_| "transfer error")?;69 <Pallet<T>>::transfer(self, &caller, &to, amount).map_err(|_| "transfer error")?;64 Ok(true)70 Ok(true)65 }71 }72 #[weight(<SelfWeightOf<T>>::transfer_from())]66 fn transfer_from(73 fn transfer_from(67 &mut self,74 &mut self,68 caller: caller,75 caller: caller,79 .map_err(dispatch_to_evm::<T>)?;86 .map_err(dispatch_to_evm::<T>)?;80 Ok(true)87 Ok(true)81 }88 }89 #[weight(<SelfWeightOf<T>>::approve())]82 fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {90 fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {83 let caller = T::CrossAccountId::from_eth(caller);91 let caller = T::CrossAccountId::from_eth(caller);84 let spender = T::CrossAccountId::from_eth(spender);92 let spender = T::CrossAccountId::from_eth(spender);89 Ok(true)97 Ok(true)90 }98 }91 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {99 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {100 self.consume_store_reads(1)?;92 let owner = T::CrossAccountId::from_eth(owner);101 let owner = T::CrossAccountId::from_eth(owner);93 let spender = T::CrossAccountId::from_eth(spender);102 let spender = T::CrossAccountId::from_eth(spender);941039810799#[solidity_interface(name = "ERC20UniqueExtensions")]108#[solidity_interface(name = "ERC20UniqueExtensions")]100impl<T: Config> FungibleHandle<T> {109impl<T: Config> FungibleHandle<T> {110 #[weight(<SelfWeightOf<T>>::burn_from())]101 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {111 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {102 let caller = T::CrossAccountId::from_eth(caller);112 let caller = T::CrossAccountId::from_eth(caller);103 let from = T::CrossAccountId::from_eth(from);113 let from = T::CrossAccountId::from_eth(from);111#[solidity_interface(name = "UniqueFungible", is(ERC20))]121#[solidity_interface(name = "UniqueFungible", is(ERC20))]112impl<T: Config> FungibleHandle<T> {}122impl<T: Config> FungibleHandle<T> {}113123114generate_stubgen!(gen_impl, UniqueFungibleCall, true);124generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);115generate_stubgen!(gen_iface, UniqueFungibleCall, false);125generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);116126117impl<T: Config> CommonEvmHandler for FungibleHandle<T> {127impl<T: Config> CommonEvmHandler for FungibleHandle<T> {118 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");128 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");119129120 fn call(mut self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileOutput> {130 fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileOutput> {121 let result = call_internal::<UniqueFungibleCall, _>(*source, &mut self, value, input);131 call::<T, UniqueFungibleCall<T>, _>(*source, self, value, input)122 self.0.recorder.evm_to_precompile_output(result)123 }132 }124}133}125134pallets/fungible/src/lib.rsdiffbeforeafterboth6use pallet_common::{6use pallet_common::{7 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, account::CrossAccountId,7 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, account::CrossAccountId,8};8};9use pallet_evm_coder_substrate::WithRecorder;9use sp_core::H160;10use sp_core::H160;10use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};11use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};11use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};12use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};82 self.083 self.083 }84 }84}85}86impl<T: Config> WithRecorder<T> for FungibleHandle<T> {87 fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {88 self.0.recorder()89 }90 fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {91 self.0.into_recorder()92 }93}85impl<T: Config> Deref for FungibleHandle<T> {94impl<T: Config> Deref for FungibleHandle<T> {86 type Target = pallet_common::CollectionHandle<T>;95 type Target = pallet_common::CollectionHandle<T>;8796136 }145 }137 <TotalSupply<T>>::insert(collection.id, total_supply);146 <TotalSupply<T>>::insert(collection.id, total_supply);138147139 collection.log_infallible(ERC20Events::Transfer {148 collection.log(ERC20Events::Transfer {140 from: *owner.as_eth(),149 from: *owner.as_eth(),141 to: H160::default(),150 to: H160::default(),142 value: amount.into(),151 value: amount.into(),180 None189 None181 };190 };182183 collection.consume_sstore()?;184 collection.consume_sstore()?;185 collection.consume_log(2, 32)?;186 collection.consume_sstore()?;187191188 // =========192 // =========189193197 <Balance<T>>::insert((collection.id, to), balance_to);201 <Balance<T>>::insert((collection.id, to), balance_to);198 }202 }199203200 collection.log_infallible(ERC20Events::Transfer {204 collection.log(ERC20Events::Transfer {201 from: *from.as_eth(),205 from: *from.as_eth(),202 to: *to.as_eth(),206 to: *to.as_eth(),203 value: amount.into(),207 value: amount.into(),217 sender: &T::CrossAccountId,221 sender: &T::CrossAccountId,218 data: Vec<CreateItemData<T>>,222 data: Vec<CreateItemData<T>>,219 ) -> DispatchResult {223 ) -> DispatchResult {220 let unrestricted_minting = collection.is_owner_or_admin(sender)?;224 if !collection.is_owner_or_admin(sender) {221 if !unrestricted_minting {222 ensure!(225 ensure!(223 collection.mint_mode,226 collection.mint_mode,224 <CommonError<T>>::PublicMintingNotAllowed227 <CommonError<T>>::PublicMintingNotAllowed241 .ok_or(ArithmeticError::Overflow)?;244 .ok_or(ArithmeticError::Overflow)?;242245243 for (user, amount) in data.into_iter() {246 for (user, amount) in data.into_iter() {244 collection.consume_sload()?;245 let balance = balances247 let balance = balances246 .entry(user.clone())248 .entry(user.clone())247 .or_insert_with(|| <Balance<T>>::get((collection.id, user)));249 .or_insert_with(|| <Balance<T>>::get((collection.id, user)));250 .ok_or(ArithmeticError::Overflow)?;252 .ok_or(ArithmeticError::Overflow)?;251 }253 }252253 collection.consume_sstore()?;254 for _ in &balances {255 collection.consume_sstore()?;256 collection.consume_log(2, 32)?;257 collection.consume_sstore()?;258 }259254260 // =========255 // =========261256262 <TotalSupply<T>>::insert(collection.id, total_supply);257 <TotalSupply<T>>::insert(collection.id, total_supply);263 for (user, amount) in balances {258 for (user, amount) in balances {264 <Balance<T>>::insert((collection.id, &user), amount);259 <Balance<T>>::insert((collection.id, &user), amount);265260266 collection.log_infallible(ERC20Events::Transfer {261 collection.log(ERC20Events::Transfer {267 from: H160::default(),262 from: H160::default(),268 to: *user.as_eth(),263 to: *user.as_eth(),269 value: amount.into(),264 value: amount.into(),287 ) {282 ) {288 <Allowance<T>>::insert((collection.id, owner, spender), amount);283 <Allowance<T>>::insert((collection.id, owner, spender), amount);289284290 collection.log_infallible(ERC20Events::Approval {285 collection.log(ERC20Events::Approval {291 owner: *owner.as_eth(),286 owner: *owner.as_eth(),292 spender: *spender.as_eth(),287 spender: *spender.as_eth(),293 value: amount.into(),288 value: amount.into(),314309315 if <Balance<T>>::get((collection.id, owner)) < amount {310 if <Balance<T>>::get((collection.id, owner)) < amount {316 ensure!(311 ensure!(317 collection.ignores_owned_amount(owner)?,312 collection.ignores_owned_amount(owner),318 <CommonError<T>>::CantApproveMoreThanOwned313 <CommonError<T>>::CantApproveMoreThanOwned319 );314 );320 }315 }343 let allowance = <Allowance<T>>::get((collection.id, from, spender)).checked_sub(amount);338 let allowance = <Allowance<T>>::get((collection.id, from, spender)).checked_sub(amount);344 if allowance.is_none() {339 if allowance.is_none() {345 ensure!(340 ensure!(346 collection.ignores_allowance(spender)?,341 collection.ignores_allowance(spender),347 <CommonError<T>>::TokenValueNotEnough342 <CommonError<T>>::TokenValueNotEnough348 );343 );349 }344 }374 let allowance = <Allowance<T>>::get((collection.id, from, spender)).checked_sub(amount);369 let allowance = <Allowance<T>>::get((collection.id, from, spender)).checked_sub(amount);375 if allowance.is_none() {370 if allowance.is_none() {376 ensure!(371 ensure!(377 collection.ignores_allowance(spender)?,372 collection.ignores_allowance(spender),378 <CommonError<T>>::TokenValueNotEnough373 <CommonError<T>>::TokenValueNotEnough379 );374 );380 }375 }pallets/nft/Cargo.tomldiffbeforeafterboth146 "serde_no_std",146 "serde_no_std",147] }147] }148148149pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }149pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }150pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }150pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }151fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }151fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }152hex-literal = "0.3.3"152hex-literal = "0.3.3"153153154pallet-common = { default-features = false, path = "../common" }154pallet-common = { default-features = false, path = "../common" }pallets/nft/src/benchmarking.rsdiffbeforeafterboth155155156 let cl = CollectionLimits {156 let cl = CollectionLimits {157 account_token_ownership_limit: Some(0),157 account_token_ownership_limit: Some(0),158 sponsored_data_size: 0,158 sponsored_data_size: Some(0),159 token_limit: 1,159 token_limit: Some(1),160 sponsor_transfer_timeout: 0,160 sponsor_transfer_timeout: Some(0),161 owner_can_destroy: true,161 owner_can_destroy: Some(true),162 owner_can_transfer: true,162 owner_can_transfer: Some(true),163 sponsored_data_rate_limit: None,163 sponsored_data_rate_limit: None,164 transfers_enabled: Some(true),164 };165 };165 }: set_collection_limits(RawOrigin::Signed(caller.clone()), collection, cl)166 }: set_collection_limits(RawOrigin::Signed(caller.clone()), collection, cl)166167pallets/nft/src/dispatch.rsdiffbeforeafterboth83 _ => {}83 _ => {}84 }84 }858586 // TODO: Make submit_logs infallible, but it shouldn't fail here anyway87 dispatched86 dispatched.into_inner().submit_logs();88 .into_inner()89 .submit_logs()90 .expect("should succeed");91 result87 result92}88}9389pallets/nft/src/eth/sponsoring.rsdiffbeforeafterboth31 let (method_id, mut reader) = AbiReader::new_call(call).map_err(|_| AnyError)?;31 let (method_id, mut reader) = AbiReader::new_call(call).map_err(|_| AnyError)?;32 match &collection.mode {32 match &collection.mode {33 crate::CollectionMode::NFT => {33 crate::CollectionMode::NFT => {34 let call: UniqueNFTCall = UniqueNFTCall::parse(method_id, &mut reader)34 let call = <UniqueNFTCall<T>>::parse(method_id, &mut reader)35 .map_err(|_| AnyError)?35 .map_err(|_| AnyError)?36 .ok_or(AnyError)?;36 .ok_or(AnyError)?;37 match call {37 match call {63 }63 }64 }64 }65 crate::CollectionMode::Fungible(_) => {65 crate::CollectionMode::Fungible(_) => {66 let call: UniqueFungibleCall = UniqueFungibleCall::parse(method_id, &mut reader)66 let call = <UniqueFungibleCall<T>>::parse(method_id, &mut reader)67 .map_err(|_| AnyError)?67 .map_err(|_| AnyError)?68 .ok_or(AnyError)?;68 .ok_or(AnyError)?;69 #[allow(clippy::single_match)]69 #[allow(clippy::single_match)]pallets/nonfungible/src/erc.rsdiffbeforeafterboth2 char::{REPLACEMENT_CHARACTER, decode_utf16},2 char::{REPLACEMENT_CHARACTER, decode_utf16},3 convert::TryInto,3 convert::TryInto,4};4};5use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*};5use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};6use frame_support::BoundedVec;6use frame_support::BoundedVec;7use nft_data_structs::TokenId;7use nft_data_structs::TokenId;8use pallet_evm_coder_substrate::dispatch_to_evm;8use pallet_evm_coder_substrate::dispatch_to_evm;9use sp_core::{H160, U256};9use sp_core::{H160, U256};10use sp_std::{vec::Vec, vec};10use sp_std::{vec::Vec, vec};11use pallet_common::{account::CrossAccountId, erc::CommonEvmHandler};11use pallet_common::{account::CrossAccountId, erc::CommonEvmHandler};12use pallet_evm_coder_substrate::call_internal;12use pallet_evm_coder_substrate::call;13use pallet_common::erc::PrecompileOutput;13use pallet_common::erc::PrecompileOutput;141415use crate::{15use crate::{16 AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,16 AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,17 SelfWeightOf, weights::WeightInfo,17};18};181919#[derive(ToLog)]20#[derive(ToLog)]64 /// Returns token's const_metadata65 /// Returns token's const_metadata65 #[solidity(rename_selector = "tokenURI")]66 #[solidity(rename_selector = "tokenURI")]66 fn token_uri(&self, token_id: uint256) -> Result<string> {67 fn token_uri(&self, token_id: uint256) -> Result<string> {68 self.consume_store_reads(1)?;67 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;69 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;68 Ok(string::from_utf8_lossy(70 Ok(string::from_utf8_lossy(69 &<TokenData<T>>::get((self.id, token_id))71 &<TokenData<T>>::get((self.id, token_id))87 }89 }889089 fn total_supply(&self) -> Result<uint256> {91 fn total_supply(&self) -> Result<uint256> {92 self.consume_store_reads(1)?;90 Ok(<Pallet<T>>::total_supply(self).into())93 Ok(<Pallet<T>>::total_supply(self).into())91 }94 }92}95}939694#[solidity_interface(name = "ERC721", events(ERC721Events))]97#[solidity_interface(name = "ERC721", events(ERC721Events))]95impl<T: Config> NonfungibleHandle<T> {98impl<T: Config> NonfungibleHandle<T> {96 fn balance_of(&self, owner: address) -> Result<uint256> {99 fn balance_of(&self, owner: address) -> Result<uint256> {100 self.consume_store_reads(1)?;97 let owner = T::CrossAccountId::from_eth(owner);101 let owner = T::CrossAccountId::from_eth(owner);98 let balance = <AccountBalance<T>>::get((self.id, owner));102 let balance = <AccountBalance<T>>::get((self.id, owner));99 Ok(balance.into())103 Ok(balance.into())100 }104 }101 fn owner_of(&self, token_id: uint256) -> Result<address> {105 fn owner_of(&self, token_id: uint256) -> Result<address> {106 self.consume_store_reads(1)?;102 let token: TokenId = token_id.try_into()?;107 let token: TokenId = token_id.try_into()?;103 Ok(*<TokenData<T>>::get((self.id, token))108 Ok(*<TokenData<T>>::get((self.id, token))104 .ok_or("token not found")?109 .ok_or("token not found")?129 Err("not implemented".into())134 Err("not implemented".into())130 }135 }131136137 #[weight(<SelfWeightOf<T>>::transfer_from())]132 fn transfer_from(138 fn transfer_from(133 &mut self,139 &mut self,134 caller: caller,140 caller: caller,147 Ok(())153 Ok(())148 }154 }149155156 #[weight(<SelfWeightOf<T>>::approve())]150 fn approve(157 fn approve(151 &mut self,158 &mut self,152 caller: caller,159 caller: caller,189196190#[solidity_interface(name = "ERC721Burnable")]197#[solidity_interface(name = "ERC721Burnable")]191impl<T: Config> NonfungibleHandle<T> {198impl<T: Config> NonfungibleHandle<T> {199 #[weight(<SelfWeightOf<T>>::burn_item())]192 fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {200 fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {193 let caller = T::CrossAccountId::from_eth(caller);201 let caller = T::CrossAccountId::from_eth(caller);194 let token = token_id.try_into()?;202 let token = token_id.try_into()?;206214207 /// `token_id` should be obtained with `next_token_id` method,215 /// `token_id` should be obtained with `next_token_id` method,208 /// unlike standard, you can't specify it manually216 /// unlike standard, you can't specify it manually217 #[weight(<SelfWeightOf<T>>::create_item())]209 fn mint(&mut self, caller: caller, to: address, token_id: uint256) -> Result<bool> {218 fn mint(&mut self, caller: caller, to: address, token_id: uint256) -> Result<bool> {210 let caller = T::CrossAccountId::from_eth(caller);219 let caller = T::CrossAccountId::from_eth(caller);211 let to = T::CrossAccountId::from_eth(to);220 let to = T::CrossAccountId::from_eth(to);235 /// `token_id` should be obtained with `next_token_id` method,244 /// `token_id` should be obtained with `next_token_id` method,236 /// unlike standard, you can't specify it manually245 /// unlike standard, you can't specify it manually237 #[solidity(rename_selector = "mintWithTokenURI")]246 #[solidity(rename_selector = "mintWithTokenURI")]247 #[weight(<SelfWeightOf<T>>::create_item())]238 fn mint_with_token_uri(248 fn mint_with_token_uri(239 &mut self,249 &mut self,240 caller: caller,250 caller: caller,276286277#[solidity_interface(name = "ERC721UniqueExtensions")]287#[solidity_interface(name = "ERC721UniqueExtensions")]278impl<T: Config> NonfungibleHandle<T> {288impl<T: Config> NonfungibleHandle<T> {289 #[weight(<SelfWeightOf<T>>::transfer())]279 fn transfer(290 fn transfer(280 &mut self,291 &mut self,281 caller: caller,292 caller: caller,291 Ok(())302 Ok(())292 }303 }293304305 #[weight(<SelfWeightOf<T>>::burn_from())]294 fn burn_from(306 fn burn_from(295 &mut self,307 &mut self,296 caller: caller,308 caller: caller,307 }319 }308320309 fn next_token_id(&self) -> Result<uint256> {321 fn next_token_id(&self) -> Result<uint256> {322 self.consume_store_reads(1)?;310 Ok(<TokensMinted<T>>::get(self.id)323 Ok(<TokensMinted<T>>::get(self.id)311 .checked_add(1)324 .checked_add(1)312 .ok_or("item id overflow")?325 .ok_or("item id overflow")?313 .into())326 .into())314 }327 }315328329 #[weight(<SelfWeightOf<T>>::set_variable_metadata(data.len() as u32))]316 fn set_variable_metadata(330 fn set_variable_metadata(317 &mut self,331 &mut self,318 caller: caller,332 caller: caller,328 }342 }329343330 fn get_variable_metadata(&self, token_id: uint256) -> Result<bytes> {344 fn get_variable_metadata(&self, token_id: uint256) -> Result<bytes> {345 self.consume_store_reads(1)?;331 let token: TokenId = token_id.try_into()?;346 let token: TokenId = token_id.try_into()?;332347333 Ok(<TokenData<T>>::get((self.id, token))348 Ok(<TokenData<T>>::get((self.id, token))334 .ok_or("token not found")?349 .ok_or("token not found")?335 .variable_data)350 .variable_data)336 }351 }337352353 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]338 fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {354 fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {339 let caller = T::CrossAccountId::from_eth(caller);355 let caller = T::CrossAccountId::from_eth(caller);340 let to = T::CrossAccountId::from_eth(to);356 let to = T::CrossAccountId::from_eth(to);363 }379 }364380365 #[solidity(rename_selector = "mintBulkWithTokenURI")]381 #[solidity(rename_selector = "mintBulkWithTokenURI")]382 #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]366 fn mint_bulk_with_token_uri(383 fn mint_bulk_with_token_uri(367 &mut self,384 &mut self,368 caller: caller,385 caller: caller,411impl<T: Config> NonfungibleHandle<T> {}428impl<T: Config> NonfungibleHandle<T> {}412429413// Not a tests, but code generators430// Not a tests, but code generators414generate_stubgen!(gen_impl, UniqueNFTCall, true);431generate_stubgen!(gen_impl, UniqueNFTCall<()>, true);415generate_stubgen!(gen_iface, UniqueNFTCall, false);432generate_stubgen!(gen_iface, UniqueNFTCall<()>, false);416417pub const CODE: &[u8] = include_bytes!("./stubs/UniqueNFT.raw");418433419impl<T: Config> CommonEvmHandler for NonfungibleHandle<T> {434impl<T: Config> CommonEvmHandler for NonfungibleHandle<T> {420 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNFT.raw");435 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNFT.raw");421436422 fn call(mut self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileOutput> {437 fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileOutput> {423 let result = call_internal::<UniqueNFTCall, _>(*source, &mut self, value, input);438 call::<T, UniqueNFTCall<T>, _>(*source, self, value, input)424 self.0.recorder.evm_to_precompile_output(result)425 }439 }426}440}427441pallets/nonfungible/src/lib.rsdiffbeforeafterboth8use pallet_common::{8use pallet_common::{9 Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, account::CrossAccountId,9 Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, account::CrossAccountId,10};10};11use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};11use sp_core::H160;12use sp_core::H160;12use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};13use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};13use sp_std::{vec::Vec, vec};14use sp_std::{vec::Vec, vec};114 self.0115 self.0115 }116 }116}117}118impl<T: Config> WithRecorder<T> for NonfungibleHandle<T> {119 fn recorder(&self) -> &SubstrateRecorder<T> {120 self.0.recorder()121 }122 fn into_recorder(self) -> SubstrateRecorder<T> {123 self.0.into_recorder()124 }125}117impl<T: Config> Deref for NonfungibleHandle<T> {126impl<T: Config> Deref for NonfungibleHandle<T> {118 type Target = pallet_common::CollectionHandle<T>;127 type Target = pallet_common::CollectionHandle<T>;119128165 ensure!(174 ensure!(166 &token_data.owner == sender175 &token_data.owner == sender167 || (collection.limits.owner_can_transfer()176 || (collection.limits.owner_can_transfer() && collection.is_owner_or_admin(sender)),168 && collection.is_owner_or_admin(sender)?),169 <CommonError<T>>::NoPermission177 <CommonError<T>>::NoPermission170 );178 );171179194 ));202 ));195 }203 }196204197 collection.log_infallible(ERC721Events::Transfer {205 collection.log(ERC721Events::Transfer {198 from: *token_data.owner.as_eth(),206 from: *token_data.owner.as_eth(),199 to: H160::default(),207 to: H160::default(),200 token_id: token.into(),208 token_id: token.into(),224 ensure!(232 ensure!(225 &token_data.owner == from233 &token_data.owner == from226 || (collection.limits.owner_can_transfer()234 || (collection.limits.owner_can_transfer() && collection.is_owner_or_admin(from)),227 && collection.is_owner_or_admin(from)?),228 <CommonError<T>>::NoPermission235 <CommonError<T>>::NoPermission229 );236 );230237252 None259 None253 };260 };254255 collection.consume_sstores(4)?;256 collection.consume_log(3, 0)?;257261258 // =========262 // =========259263278 }282 }279 Self::set_allowance_unchecked(collection, from, token, None, true);283 Self::set_allowance_unchecked(collection, from, token, None, true);280284281 collection.log_infallible(ERC721Events::Transfer {285 collection.log(ERC721Events::Transfer {282 from: *from.as_eth(),286 from: *from.as_eth(),283 to: *to.as_eth(),287 to: *to.as_eth(),284 token_id: token.into(),288 token_id: token.into(),298 sender: &T::CrossAccountId,302 sender: &T::CrossAccountId,299 data: Vec<CreateItemData<T>>,303 data: Vec<CreateItemData<T>>,300 ) -> DispatchResult {304 ) -> DispatchResult {301 let unrestricted_minting = collection.is_owner_or_admin(sender)?;305 if !collection.is_owner_or_admin(sender) {302 if !unrestricted_minting {303 ensure!(306 ensure!(304 collection.mint_mode,307 collection.mint_mode,305 <CommonError<T>>::PublicMintingNotAllowed308 <CommonError<T>>::PublicMintingNotAllowed313316314 for data in data.iter() {317 for data in data.iter() {315 <PalletCommon<T>>::ensure_correct_receiver(&data.owner)?;318 <PalletCommon<T>>::ensure_correct_receiver(&data.owner)?;316 if !data.const_data.is_empty() {317 collection.consume_sstore()?;318 }319 if !data.variable_data.is_empty() {320 collection.consume_sstore()?;321 }322 collection.consume_sstore()?;323 collection.consume_log(3, 0)?;324 }319 }325320326 let first_token = <TokensMinted<T>>::get(collection.id);321 let first_token = <TokensMinted<T>>::get(collection.id);331 tokens_minted < collection.limits.token_limit(),326 tokens_minted < collection.limits.token_limit(),332 <CommonError<T>>::CollectionTokenLimitExceeded327 <CommonError<T>>::CollectionTokenLimitExceeded333 );328 );334 collection.consume_sstore()?;335329336 let mut balances = BTreeMap::new();330 let mut balances = BTreeMap::new();337 for data in &data {331 for data in &data {345 <CommonError<T>>::AccountTokenLimitExceeded,339 <CommonError<T>>::AccountTokenLimitExceeded,346 );340 );347 }341 }348 collection.consume_sstores(balances.len())?;349342350 // =========343 // =========351344366 );359 );367 <Owned<T>>::insert((collection.id, &data.owner, token), true);360 <Owned<T>>::insert((collection.id, &data.owner, token), true);368361369 collection.log_infallible(ERC721Events::Transfer {362 collection.log(ERC721Events::Transfer {370 from: H160::default(),363 from: H160::default(),371 to: *data.owner.as_eth(),364 to: *data.owner.as_eth(),372 token_id: token.into(),365 token_id: token.into(),393 <Allowance<T>>::insert((collection.id, token), spender);386 <Allowance<T>>::insert((collection.id, token), spender);394 // In ERC721 there is only one possible approved user of token, so we set387 // In ERC721 there is only one possible approved user of token, so we set395 // approved user to spender388 // approved user to spender396 collection.log_infallible(ERC721Events::Approval {389 collection.log(ERC721Events::Approval {397 owner: *sender.as_eth(),390 owner: *sender.as_eth(),398 approved: *spender.as_eth(),391 approved: *spender.as_eth(),399 token_id: token.into(),392 token_id: token.into(),423 if !assume_implicit_eth {416 if !assume_implicit_eth {424 // In ERC721 there is only one possible approved user of token, so we set417 // In ERC721 there is only one possible approved user of token, so we set425 // approved user to zero address418 // approved user to zero address426 collection.log_infallible(ERC721Events::Approval {419 collection.log(ERC721Events::Approval {427 owner: *sender.as_eth(),420 owner: *sender.as_eth(),428 approved: H160::default(),421 approved: H160::default(),429 token_id: token.into(),422 token_id: token.into(),463 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;456 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;464 if &token_data.owner != sender {457 if &token_data.owner != sender {465 ensure!(458 ensure!(466 collection.ignores_owned_amount(sender)?,459 collection.ignores_owned_amount(sender),467 <CommonError<T>>::CantApproveMoreThanOwned460 <CommonError<T>>::CantApproveMoreThanOwned468 );461 );469 }462 }491484492 if <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {485 if <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {493 ensure!(486 ensure!(494 collection.ignores_allowance(spender)?,487 collection.ignores_allowance(spender),495 <CommonError<T>>::TokenValueNotEnough488 <CommonError<T>>::TokenValueNotEnough496 );489 );497 }490 }519512520 if <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {513 if <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {521 ensure!(514 ensure!(522 collection.ignores_allowance(spender)?,515 collection.ignores_allowance(spender),523 <CommonError<T>>::TokenValueNotEnough516 <CommonError<T>>::TokenValueNotEnough524 );517 );525 }518 }543 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;536 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;544 collection.check_can_update_meta(sender, &token_data.owner)?;537 collection.check_can_update_meta(sender, &token_data.owner)?;545546 collection.consume_sstore()?;547538548 // =========539 // =========549540pallets/refungible/src/common.rsdiffbeforeafterboth58 }58 }595960 fn burn_from() -> Weight {60 fn burn_from() -> Weight {61 061 <SelfWeightOf<T>>::burn_from()62 }62 }636364 fn set_variable_metadata(bytes: u32) -> Weight {64 fn set_variable_metadata(bytes: u32) -> Weight {pallets/refungible/src/lib.rsdiffbeforeafterboth359 sender: &T::CrossAccountId,359 sender: &T::CrossAccountId,360 data: Vec<CreateItemData<T>>,360 data: Vec<CreateItemData<T>>,361 ) -> DispatchResult {361 ) -> DispatchResult {362 let unrestricted_minting = collection.is_owner_or_admin(sender)?;362 if !collection.is_owner_or_admin(sender) {363 if !unrestricted_minting {364 ensure!(363 ensure!(365 collection.mint_mode,364 collection.mint_mode,366 <CommonError<T>>::PublicMintingNotAllowed365 <CommonError<T>>::PublicMintingNotAllowed492491493 if <Balance<T>>::get((collection.id, token, sender)) < amount {492 if <Balance<T>>::get((collection.id, token, sender)) < amount {494 ensure!(493 ensure!(495 collection.ignores_owned_amount(sender)? && Self::token_exists(collection, token),494 collection.ignores_owned_amount(sender) && Self::token_exists(collection, token),496 <CommonError<T>>::CantApproveMoreThanOwned495 <CommonError<T>>::CantApproveMoreThanOwned497 );496 );498 }497 }523 <Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);522 <Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);524 if allowance.is_none() {523 if allowance.is_none() {525 ensure!(524 ensure!(526 collection.ignores_allowance(spender)?,525 collection.ignores_allowance(spender),527 <CommonError<T>>::TokenValueNotEnough526 <CommonError<T>>::TokenValueNotEnough528 );527 );529 }528 }556 <Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);555 <Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);557 if allowance.is_none() {556 if allowance.is_none() {558 ensure!(557 ensure!(559 collection.ignores_allowance(spender)?,558 collection.ignores_allowance(spender),560 <CommonError<T>>::TokenValueNotEnough559 <CommonError<T>>::TokenValueNotEnough561 );560 );562 }561 }585 &T::CrossAccountId::from_sub(collection.owner.clone()),584 &T::CrossAccountId::from_sub(collection.owner.clone()),586 )?;585 )?;587586588 collection.consume_sstore()?;589 let token_data = <TokenData<T>>::get((collection.id, token));587 let token_data = <TokenData<T>>::get((collection.id, token));590588591 // =========589 // =========runtime/Cargo.tomldiffbeforeafterboth387pallet-evm-transaction-payment = { path = '../pallets/evm-transaction-payment', default-features = false }387pallet-evm-transaction-payment = { path = '../pallets/evm-transaction-payment', default-features = false }388pallet-evm-coder-substrate = { default-features = false, path = "../pallets/evm-coder-substrate" }388pallet-evm-coder-substrate = { default-features = false, path = "../pallets/evm-coder-substrate" }389389390pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }390pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }391pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }391pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }392fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }392fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }393fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }393fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }394394395################################################################################395################################################################################396# Build Dependencies396# Build Dependenciesruntime/src/lib.rsdiffbeforeafterboth66};66};67use smallvec::smallvec;67use smallvec::smallvec;68use codec::{Encode, Decode};68use codec::{Encode, Decode};69use pallet_evm::{Account as EVMAccount, FeeCalculator, OnMethodCall};69use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping, OnMethodCall};70use fp_rpc::TransactionStatus;70use fp_rpc::TransactionStatus;71use sp_core::crypto::Public;71use sp_core::crypto::Public;72use sp_runtime::{72use sp_runtime::{247 }247 }248}248}249250// Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case251// (contract, which only writes a lot of data),252// approximating on top of our real store write weight253parameter_types! {254 pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND / <Runtime as frame_system::Config>::DbWeight::get().write;255 pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000;256 pub const WeightPerGas: u64 = WEIGHT_PER_SECOND / GasPerSecond::get();257}258259/// Limiting EVM execution to 50% of block for substrate users and management tasks260/// EVM transaction consumes more weight than substrate's, so we can't rely on them being261/// scheduled fairly262const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);263parameter_types! {264 pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get());265}266267pub enum FixedGasWeightMapping {}268impl GasWeightMapping for FixedGasWeightMapping {269 fn gas_to_weight(gas: u64) -> Weight {270 gas.saturating_mul(WeightPerGas::get())271 }272 fn weight_to_gas(weight: Weight) -> u64 {273 weight / WeightPerGas::get()274 }275}249276250impl pallet_evm::Config for Runtime {277impl pallet_evm::Config for Runtime {251 type BlockGasLimit = BlockGasLimit;278 type BlockGasLimit = BlockGasLimit;252 type FeeCalculator = FixedFee;279 type FeeCalculator = FixedFee;253 type GasWeightMapping = ();280 type GasWeightMapping = FixedGasWeightMapping;254 type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;281 type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;255 type CallOrigin = EnsureAddressTruncated;282 type CallOrigin = EnsureAddressTruncated;256 type WithdrawOrigin = EnsureAddressTruncated;283 type WithdrawOrigin = EnsureAddressTruncated;289 }316 }290}317}291292parameter_types! {293 pub BlockGasLimit: U256 = U256::from(u32::max_value());294}295318296impl pallet_ethereum::Config for Runtime {319impl pallet_ethereum::Config for Runtime {297 type Event = Event;320 type Event = Event;298 type StateRoot = pallet_ethereum::IntermediateStateRoot;321 type StateRoot = pallet_ethereum::IntermediateStateRoot;299 type EvmSubmitLog = pallet_evm::Pallet<Self>;300}322}301323302impl pallet_randomness_collective_flip::Config for Runtime {}324impl pallet_randomness_collective_flip::Config for Runtime {}671693672impl pallet_evm_coder_substrate::Config for Runtime {694impl pallet_evm_coder_substrate::Config for Runtime {673 type EthereumTransactionSender = pallet_ethereum::Pallet<Self>;695 type EthereumTransactionSender = pallet_ethereum::Pallet<Self>;696 type GasWeightMapping = FixedGasWeightMapping;674}697}675698676impl pallet_xcm::Config for Runtime {699impl pallet_xcm::Config for Runtime {