difftreelog
feat implement #[weight] macro for evm support
in: master
35 files changed
crates/evm-coder-macros/src/lib.rsdiffbeforeafterboth--- a/crates/evm-coder-macros/src/lib.rs
+++ b/crates/evm-coder-macros/src/lib.rs
@@ -211,6 +211,10 @@
pub fn solidity(_args: TokenStream, stream: TokenStream) -> TokenStream {
stream
}
+#[proc_macro_attribute]
+pub fn weight(_args: TokenStream, stream: TokenStream) -> TokenStream {
+ stream
+}
#[proc_macro_derive(ToLog, attributes(indexed))]
pub fn to_log(value: TokenStream) -> TokenStream {
crates/evm-coder-macros/src/solidity_interface.rsdiffbeforeafterboth--- a/crates/evm-coder-macros/src/solidity_interface.rs
+++ b/crates/evm-coder-macros/src/solidity_interface.rs
@@ -30,11 +30,11 @@
})
}
- fn expand_call_def(&self) -> proc_macro2::TokenStream {
+ fn expand_call_def(&self, gen_ref: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
let name = &self.name;
let pascal_call_name = &self.pascal_call_name;
quote! {
- #name(#pascal_call_name)
+ #name(#pascal_call_name #gen_ref)
}
}
@@ -45,18 +45,32 @@
}
}
- fn expand_supports_interface(&self) -> proc_macro2::TokenStream {
+ fn expand_supports_interface(
+ &self,
+ generics: &proc_macro2::TokenStream,
+ ) -> proc_macro2::TokenStream {
let pascal_call_name = &self.pascal_call_name;
quote! {
- #pascal_call_name::supports_interface(interface_id)
+ <#pascal_call_name #generics>::supports_interface(interface_id)
+ }
+ }
+
+ fn expand_variant_weight(&self) -> proc_macro2::TokenStream {
+ let name = &self.name;
+ quote! {
+ Self::#name(call) => call.weight()
}
}
- fn expand_variant_call(&self) -> proc_macro2::TokenStream {
+ fn expand_variant_call(
+ &self,
+ call_name: &proc_macro2::Ident,
+ generics: &proc_macro2::TokenStream,
+ ) -> proc_macro2::TokenStream {
let name = &self.name;
let pascal_call_name = &self.pascal_call_name;
quote! {
- InternalCall::#name(call) => return <Self as ::evm_coder::Callable<#pascal_call_name>>::call(self, Msg {
+ #call_name::#name(call) => return <Self as ::evm_coder::Callable<#pascal_call_name #generics>>::call(self, Msg {
call,
caller: c.caller,
value: c.value,
@@ -64,20 +78,20 @@
}
}
- fn expand_parse(&self) -> proc_macro2::TokenStream {
+ fn expand_parse(&self, generics: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
let name = &self.name;
let pascal_call_name = &self.pascal_call_name;
quote! {
- if let Some(parsed_call) = #pascal_call_name::parse(method_id, reader)? {
+ if let Some(parsed_call) = <#pascal_call_name #generics>::parse(method_id, reader)? {
return Ok(Some(Self::#name(parsed_call)))
}
}
}
- fn expand_generator(&self) -> proc_macro2::TokenStream {
+ fn expand_generator(&self, generics: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
let pascal_call_name = &self.pascal_call_name;
quote! {
- #pascal_call_name::generate_solidity_interface(tc, is_impl);
+ <#pascal_call_name #generics>::generate_solidity_interface(tc, is_impl);
}
}
@@ -351,6 +365,25 @@
Pure,
}
+pub struct WeightAttr(syn::Expr);
+
+mod keyword {
+ syn::custom_keyword!(weight);
+}
+
+impl syn::parse::Parse for WeightAttr {
+ fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+ input.parse::<syn::Token![#]>()?;
+ let content;
+ syn::bracketed!(content in input);
+ content.parse::<keyword::weight>()?;
+
+ let weight_content;
+ syn::parenthesized!(weight_content in content);
+ Ok(WeightAttr(weight_content.parse::<syn::Expr>()?))
+ }
+}
+
struct Method {
name: Ident,
camel_name: String,
@@ -362,6 +395,7 @@
has_normal_args: bool,
mutability: Mutability,
result: Type,
+ weight: Option<Expr>,
docs: Vec<String>,
}
impl Method {
@@ -370,6 +404,7 @@
rename_selector: None,
};
let mut docs = Vec::new();
+ let mut weight = None;
for attr in &value.attrs {
let ident = parse_ident_from_path(&attr.path, false)?;
if ident == "solidity" {
@@ -384,6 +419,8 @@
_ => unreachable!(),
};
docs.push(value);
+ } else if ident == "weight" {
+ weight = Some(syn::parse2::<WeightAttr>(attr.to_token_stream())?.0);
}
}
let ident = &value.sig.ident;
@@ -466,6 +503,7 @@
has_normal_args,
mutability,
result: result.clone(),
+ weight,
docs,
})
}
@@ -528,7 +566,7 @@
}
}
- fn expand_variant_call(&self) -> proc_macro2::TokenStream {
+ fn expand_variant_call(&self, call_name: &proc_macro2::Ident) -> proc_macro2::TokenStream {
let pascal_name = &self.pascal_name;
let name = &self.name;
@@ -555,17 +593,50 @@
let args = self.args.iter().map(|a| a.expand_call_arg());
quote! {
- InternalCall::#pascal_name #matcher => {
+ #call_name::#pascal_name #matcher => {
let result = #receiver #name(
#(
#args,
)*
)?;
- (&result).abi_write(&mut writer);
+ (&result).into_result()
}
}
}
+ fn expand_variant_weight(&self) -> proc_macro2::TokenStream {
+ let pascal_name = &self.pascal_name;
+ if let Some(weight) = &self.weight {
+ let matcher = if self.has_normal_args {
+ let names = self
+ .args
+ .iter()
+ .filter(|a| !a.is_special())
+ .map(|a| &a.name);
+
+ quote! {{
+ #(
+ #names,
+ )*
+ }}
+ } else {
+ quote! {}
+ };
+ quote! {
+ Self::#pascal_name #matcher => (#weight).into()
+ }
+ } else {
+ let matcher = if self.has_normal_args {
+ quote! {{..}}
+ } else {
+ quote! {}
+ };
+ quote! {
+ Self::#pascal_name #matcher => ().into()
+ }
+ }
+ }
+
fn expand_solidity_function(&self) -> proc_macro2::TokenStream {
let camel_name = &self.camel_name;
let mutability = match self.mutability {
@@ -600,6 +671,42 @@
}
}
+fn generics_list(gen: &Generics) -> proc_macro2::TokenStream {
+ if gen.params.is_empty() {
+ return quote! {};
+ }
+ let params = gen.params.iter().map(|p| match p {
+ syn::GenericParam::Type(id) => {
+ let v = &id.ident;
+ quote! {#v}
+ }
+ syn::GenericParam::Lifetime(lt) => {
+ let v = <.lifetime;
+ quote! {#v}
+ }
+ syn::GenericParam::Const(c) => {
+ let i = &c.ident;
+ quote! {#i}
+ }
+ });
+ quote! { #(#params),* }
+}
+fn generics_reference(gen: &Generics) -> proc_macro2::TokenStream {
+ if gen.params.is_empty() {
+ return quote! {};
+ }
+ let list = generics_list(gen);
+ quote! { <#list> }
+}
+fn generics_data(gen: &Generics) -> proc_macro2::TokenStream {
+ let list = generics_list(gen);
+ if gen.params.len() == 1 {
+ quote! {#list}
+ } else {
+ quote! { (#list) }
+ }
+}
+
pub struct SolidityInterface {
generics: Generics,
name: Box<syn::Type>,
@@ -628,6 +735,8 @@
let solidity_name = self.info.name.to_string();
let call_name = pascal_ident_to_call(&self.info.name);
let generics = self.generics;
+ let gen_ref = generics_reference(&generics);
+ let gen_data = generics_data(&generics);
let call_sub = self
.info
@@ -635,30 +744,46 @@
.0
.iter()
.chain(self.info.is.0.iter())
- .map(Is::expand_call_def);
+ .map(|c| Is::expand_call_def(c, &gen_ref));
let call_parse = self
.info
.inline_is
.0
.iter()
.chain(self.info.is.0.iter())
- .map(Is::expand_parse);
+ .map(|is| Is::expand_parse(is, &gen_ref));
let call_variants = self
.info
.inline_is
.0
.iter()
.chain(self.info.is.0.iter())
- .map(Is::expand_variant_call);
+ .map(|c| Is::expand_variant_call(c, &call_name, &gen_ref));
+ let weight_variants = self
+ .info
+ .inline_is
+ .0
+ .iter()
+ .chain(self.info.is.0.iter())
+ .map(Is::expand_variant_weight);
let inline_interface_id = self.info.inline_is.0.iter().map(Is::expand_interface_id);
- let supports_interface = self.info.is.0.iter().map(Is::expand_supports_interface);
+ let supports_interface = self
+ .info
+ .is
+ .0
+ .iter()
+ .map(|is| Is::expand_supports_interface(is, &gen_ref));
let calls = self.methods.iter().map(Method::expand_call_def);
let consts = self.methods.iter().map(Method::expand_const);
let interface_id = self.methods.iter().map(Method::expand_interface_id);
let parsers = self.methods.iter().map(Method::expand_parse);
- let call_variants_this = self.methods.iter().map(Method::expand_variant_call);
+ let call_variants_this = self
+ .methods
+ .iter()
+ .map(|m| Method::expand_variant_call(m, &call_name));
+ let weight_variants_this = self.methods.iter().map(Method::expand_variant_weight);
let solidity_functions = self.methods.iter().map(Method::expand_solidity_function);
// TODO: Inline inline_is
@@ -676,15 +801,15 @@
.0
.iter()
.chain(self.info.inline_is.0.iter())
- .map(Is::expand_generator);
+ .map(|is| Is::expand_generator(is, &gen_ref));
let solidity_event_generators = self.info.events.0.iter().map(Is::expand_event_generator);
// let methods = self.methods.iter().map(Method::solidity_def);
quote! {
#[derive(Debug)]
- pub enum #call_name {
- ERC165Call(::evm_coder::ERC165Call),
+ pub enum #call_name #gen_ref {
+ ERC165Call(::evm_coder::ERC165Call, ::core::marker::PhantomData<#gen_data>),
#(
#calls,
)*
@@ -692,11 +817,11 @@
#call_sub,
)*
}
- impl #call_name {
+ impl #gen_ref #call_name #gen_ref {
#(
#consts
)*
- pub const fn interface_id() -> u32 {
+ pub fn interface_id() -> u32 {
let mut interface_id = 0;
#(#interface_id)*
#(#inline_interface_id)*
@@ -748,11 +873,14 @@
tc.collect(out);
}
}
- impl ::evm_coder::Call for #call_name {
+ impl #gen_ref ::evm_coder::Call for #call_name #gen_ref {
fn parse(method_id: u32, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {
use ::evm_coder::abi::AbiRead;
match method_id {
- ::evm_coder::ERC165Call::INTERFACE_ID => return Ok(::evm_coder::ERC165Call::parse(method_id, reader)?.map(Self::ERC165Call)),
+ ::evm_coder::ERC165Call::INTERFACE_ID => return Ok(
+ ::evm_coder::ERC165Call::parse(method_id, reader)?
+ .map(|c| Self::ERC165Call(c, ::core::marker::PhantomData))
+ ),
#(
#parsers,
)*
@@ -764,19 +892,33 @@
return Ok(None);
}
}
- impl #generics ::evm_coder::Callable<#call_name> for #name {
+ impl #generics ::evm_coder::Weighted for #call_name #gen_ref {
+ #[allow(unused_variables)]
+ fn weight(&self) -> ::evm_coder::execution::DispatchInfo {
+ match self {
+ #(
+ #weight_variants,
+ )*
+ // TODO: It should be very cheap, but not free
+ Self::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {..}, _) => 100u64.into(),
+ #(
+ #weight_variants_this,
+ )*
+ }
+ }
+ }
+ impl #generics ::evm_coder::Callable<#call_name #gen_ref> for #name {
#[allow(unreachable_code)] // In case of no inner calls
- fn call(&mut self, c: Msg<#call_name>) -> Result<::evm_coder::abi::AbiWriter> {
+ fn call(&mut self, c: Msg<#call_name #gen_ref>) -> ::evm_coder::execution::ResultWithPostInfo<::evm_coder::abi::AbiWriter> {
use ::evm_coder::abi::AbiWrite;
- type InternalCall = #call_name;
match c.call {
#(
#call_variants,
)*
- InternalCall::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {interface_id}) => {
+ #call_name::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {interface_id}, _) => {
let mut writer = ::evm_coder::abi::AbiWriter::default();
- writer.bool(&InternalCall::supports_interface(interface_id));
- return Ok(writer);
+ writer.bool(&<#call_name #gen_ref>::supports_interface(interface_id));
+ return Ok(writer.into());
}
_ => {},
}
@@ -787,7 +929,6 @@
)*
_ => unreachable!()
}
- Ok(writer)
}
}
}
crates/evm-coder/src/abi.rsdiffbeforeafterboth--- a/crates/evm-coder/src/abi.rs
+++ b/crates/evm-coder/src/abi.rs
@@ -11,7 +11,10 @@
use evm_core::ExitError;
use primitive_types::{H160, U256};
-use crate::{execution::Error, types::string};
+use crate::{
+ execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},
+ types::string,
+};
use crate::execution::Result;
const ABI_ALIGNMENT: usize = 32;
@@ -244,6 +247,7 @@
}
impl_abi_readable!(u32, uint32);
+impl_abi_readable!(u64, uint64);
impl_abi_readable!(u128, uint128);
impl_abi_readable!(U256, uint256);
impl_abi_readable!(H160, address);
@@ -306,6 +310,36 @@
pub trait AbiWrite {
fn abi_write(&self, writer: &mut AbiWriter);
+ fn into_result(&self) -> ResultWithPostInfo<AbiWriter> {
+ let mut writer = AbiWriter::new();
+ self.abi_write(&mut writer);
+ Ok(writer.into())
+ }
+}
+
+impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {
+ // this particular AbiWrite implementation should be split to another trait,
+ // which only implements [`into_result`]
+ //
+ // But due to lack of specialization feature in stable Rust, we can't have
+ // blanket impl of this trait `for T where T: AbiWrite`, so here we abusing
+ // default trait methods for it
+ fn abi_write(&self, _writer: &mut AbiWriter) {
+ debug_assert!(false, "shouldn't be called, see comment")
+ }
+ fn into_result(&self) -> ResultWithPostInfo<AbiWriter> {
+ match self {
+ Ok(v) => Ok(WithPostDispatchInfo {
+ post_info: v.post_info.clone(),
+ data: {
+ let mut out = AbiWriter::new();
+ v.data.abi_write(&mut out);
+ out
+ },
+ }),
+ Err(e) => Err(e.clone()),
+ }
+ }
}
macro_rules! impl_abi_writeable {
crates/evm-coder/src/execution.rsdiffbeforeafterboth--- a/crates/evm-coder/src/execution.rs
+++ b/crates/evm-coder/src/execution.rs
@@ -4,7 +4,9 @@
#[cfg(feature = "std")]
use std::string::{String, ToString};
-#[derive(Debug)]
+use crate::Weight;
+
+#[derive(Debug, Clone)]
pub enum Error {
Revert(String),
Fatal(ExitFatal),
@@ -21,3 +23,55 @@
}
pub type Result<T> = core::result::Result<T, Error>;
+
+pub struct DispatchInfo {
+ pub weight: Weight,
+}
+
+impl From<Weight> for DispatchInfo {
+ fn from(weight: Weight) -> Self {
+ Self { weight }
+ }
+}
+impl From<()> for DispatchInfo {
+ fn from(_: ()) -> Self {
+ Self { weight: 0 }
+ }
+}
+
+#[derive(Default, Clone)]
+pub struct PostDispatchInfo {
+ actual_weight: Option<Weight>,
+}
+
+impl PostDispatchInfo {
+ pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight {
+ info.weight - self.calc_actual_weight(info)
+ }
+
+ pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight {
+ if let Some(actual_weight) = self.actual_weight {
+ actual_weight.min(info.weight)
+ } else {
+ info.weight
+ }
+ }
+}
+
+#[derive(Clone)]
+pub struct WithPostDispatchInfo<T> {
+ pub data: T,
+ pub post_info: PostDispatchInfo,
+}
+
+impl<T> From<T> for WithPostDispatchInfo<T> {
+ fn from(data: T) -> Self {
+ Self {
+ data,
+ post_info: Default::default(),
+ }
+ }
+}
+
+pub type ResultWithPostInfo<T> =
+ core::result::Result<WithPostDispatchInfo<T>, WithPostDispatchInfo<Error>>;
crates/evm-coder/src/lib.rsdiffbeforeafterboth--- a/crates/evm-coder/src/lib.rs
+++ b/crates/evm-coder/src/lib.rs
@@ -3,10 +3,11 @@
extern crate alloc;
use abi::{AbiRead, AbiReader, AbiWriter};
-pub use evm_coder_macros::{event_topic, fn_selector, solidity_interface, solidity, ToLog};
+pub use evm_coder_macros::{event_topic, fn_selector, solidity_interface, solidity, weight, ToLog};
pub mod abi;
pub mod events;
pub use events::ToLog;
+use execution::DispatchInfo;
pub mod execution;
pub mod solidity;
@@ -57,8 +58,14 @@
fn parse(selector: u32, input: &mut AbiReader) -> execution::Result<Option<Self>>;
}
+pub type Weight = u64;
+
+pub trait Weighted: Call {
+ fn weight(&self) -> DispatchInfo;
+}
+
pub trait Callable<C: Call> {
- fn call(&mut self, call: types::Msg<C>) -> execution::Result<AbiWriter>;
+ fn call(&mut self, call: types::Msg<C>) -> execution::ResultWithPostInfo<AbiWriter>;
}
/// Implementation is implicitly provided for all interfaces
@@ -84,15 +91,20 @@
}
}
+/// Generate "tests", which will generate solidity code on execution and print it to stdout
+/// Script at .maintain/scripts/generate_api.sh can split this output from test runtime
+///
+/// This macro receives type usage as second argument, but you can use anything as generics,
+/// because no bounds are implied
#[macro_export]
macro_rules! generate_stubgen {
- ($name:ident, $decl:ident, $is_impl:literal) => {
+ ($name:ident, $decl:ty, $is_impl:literal) => {
#[test]
#[ignore]
fn $name() {
use evm_coder::solidity::TypeCollector;
let mut out = TypeCollector::new();
- $decl::generate_solidity_interface(&mut out, $is_impl);
+ <$decl>::generate_solidity_interface(&mut out, $is_impl);
println!("=== SNIP START ===");
println!("// SPDX-License-Identifier: OTHER");
println!("// This code is automatically generated");
crates/evm-coder/tests/a.rsdiffbeforeafterboth--- a/crates/evm-coder/tests/a.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-#![allow(dead_code)] // This test only checks that macros is not panicking
-
-use evm_coder::{solidity_interface, types::*, ToLog, execution::Result};
-use evm_coder_macros::solidity;
-
-struct Impls;
-
-#[solidity_interface(name = "OurInterface")]
-impl Impls {
- fn fn_a(&self, _input: uint256) -> Result<bool> {
- todo!()
- }
-}
-
-#[solidity_interface(name = "OurInterface1")]
-impl Impls {
- fn fn_b(&self, _input: uint128) -> Result<uint32> {
- todo!()
- }
-}
-
-#[solidity_interface(
- name = "OurInterface2",
- is(OurInterface),
- inline_is(OurInterface1),
- events(ERC721Log)
-)]
-impl Impls {
- #[solidity(rename_selector = "fnK")]
- fn fn_c(&self, _input: uint32) -> Result<uint8> {
- todo!()
- }
- fn fn_d(&self, _value: uint32) -> Result<uint32> {
- todo!()
- }
-
- fn caller_sensitive(&self, _caller: caller) -> Result<uint8> {
- todo!()
- }
- fn payable(&mut self, _value: value) -> Result<uint8> {
- todo!()
- }
-}
-
-#[derive(ToLog)]
-enum ERC721Log {
- Transfer {
- #[indexed]
- from: address,
- #[indexed]
- to: address,
- value: uint256,
- },
- Eee {
- #[indexed]
- aaa: address,
- bbb: uint256,
- },
-}
-
-struct ERC20;
-
-#[solidity_interface(name = "ERC20")]
-impl ERC20 {
- fn decimals(&self) -> Result<uint8> {
- todo!()
- }
- fn balance_of(&self, _owner: address) -> Result<uint256> {
- todo!()
- }
- fn transfer(&mut self, _caller: caller, _to: address, _value: uint256) -> Result<bool> {
- todo!()
- }
- fn transfer_from(
- &mut self,
- _caller: caller,
- _from: address,
- _to: address,
- _value: uint256,
- ) -> Result<bool> {
- todo!()
- }
- fn approve(&mut self, _caller: caller, _spender: address, _value: uint256) -> Result<bool> {
- todo!()
- }
- fn allowance(&self, _owner: address, _spender: address) -> Result<uint256> {
- todo!()
- }
-}
crates/evm-coder/tests/generics.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/evm-coder/tests/generics.rs
@@ -0,0 +1,20 @@
+use std::marker::PhantomData;
+use evm_coder::{execution::Result, generate_stubgen, solidity_interface, types::*};
+
+struct Generic<T>(PhantomData<T>);
+
+#[solidity_interface(name = "GenericIs")]
+impl<T> Generic<T> {
+ fn test_1(&self) -> Result<uint256> {
+ todo!()
+ }
+}
+
+#[solidity_interface(name = "Generic", is(GenericIs))]
+impl<T: Into<u32>> Generic<T> {
+ fn test_2(&self) -> Result<uint256> {
+ todo!()
+ }
+}
+
+generate_stubgen!(gen_iface, GenericCall<()>, false);
crates/evm-coder/tests/log.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/evm-coder/tests/log.rs
@@ -0,0 +1,17 @@
+use evm_coder::{ToLog, types::*};
+
+#[derive(ToLog)]
+enum ERC721Log {
+ Transfer {
+ #[indexed]
+ from: address,
+ #[indexed]
+ to: address,
+ value: uint256,
+ },
+ Eee {
+ #[indexed]
+ aaa: address,
+ bbb: uint256,
+ },
+}
crates/evm-coder/tests/random.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/evm-coder/tests/random.rs
@@ -0,0 +1,65 @@
+#![allow(dead_code)] // This test only checks that macros is not panicking
+
+use evm_coder::{ToLog, execution::Result, solidity_interface, types::*};
+use evm_coder_macros::{solidity, weight};
+
+struct Impls;
+
+#[solidity_interface(name = "OurInterface")]
+impl Impls {
+ fn fn_a(&self, _input: uint256) -> Result<bool> {
+ todo!()
+ }
+}
+
+#[solidity_interface(name = "OurInterface1")]
+impl Impls {
+ fn fn_b(&self, _input: uint128) -> Result<uint32> {
+ todo!()
+ }
+}
+
+#[derive(ToLog)]
+enum OurEvents {
+ Event1 {
+ field1: uint32,
+ },
+ Event2 {
+ field1: uint32,
+ #[indexed]
+ field2: uint32,
+ },
+}
+
+#[solidity_interface(
+ name = "OurInterface2",
+ is(OurInterface),
+ inline_is(OurInterface1),
+ events(OurEvents)
+)]
+impl Impls {
+ #[solidity(rename_selector = "fnK")]
+ fn fn_c(&self, _input: uint32) -> Result<uint8> {
+ todo!()
+ }
+ fn fn_d(&self, _value: uint32) -> Result<uint32> {
+ todo!()
+ }
+
+ fn caller_sensitive(&self, _caller: caller) -> Result<uint8> {
+ todo!()
+ }
+ fn payable(&mut self, _value: value) -> Result<uint8> {
+ todo!()
+ }
+
+ #[weight(*_weight)]
+ fn with_weight(&self, _weight: uint64) -> Result<void> {
+ todo!()
+ }
+
+ /// Doccoment example
+ fn with_doc(&self) -> Result<void> {
+ todo!()
+ }
+}
crates/evm-coder/tests/solidity_generation.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/evm-coder/tests/solidity_generation.rs
@@ -0,0 +1,35 @@
+use evm_coder::{execution::Result, generate_stubgen, solidity_interface, types::*};
+
+struct ERC20;
+
+#[solidity_interface(name = "ERC20")]
+impl ERC20 {
+ fn decimals(&self) -> Result<uint8> {
+ todo!()
+ }
+ /// Get balance of specified owner
+ fn balance_of(&self, _owner: address) -> Result<uint256> {
+ todo!()
+ }
+ fn transfer(&mut self, _caller: caller, _to: address, _value: uint256) -> Result<bool> {
+ todo!()
+ }
+ fn transfer_from(
+ &mut self,
+ _caller: caller,
+ _from: address,
+ _to: address,
+ _value: uint256,
+ ) -> Result<bool> {
+ todo!()
+ }
+ fn approve(&mut self, _caller: caller, _spender: address, _value: uint256) -> Result<bool> {
+ todo!()
+ }
+ fn allowance(&self, _owner: address, _spender: address) -> Result<uint256> {
+ todo!()
+ }
+}
+
+generate_stubgen!(gen_impl, ERC20Call, true);
+generate_stubgen!(gen_iface, ERC20Call, false);
node/cli/Cargo.tomldiffbeforeafterboth--- a/node/cli/Cargo.toml
+++ b/node/cli/Cargo.toml
@@ -268,13 +268,13 @@
jsonrpc-core = '18.0.0'
jsonrpc-pubsub = "18.0.0"
-fc-rpc-core = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-consensus = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-mapping-sync = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-db = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fp-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+fc-rpc-core = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-consensus = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-mapping-sync = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-db = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fp-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
nft-rpc = { path = "../rpc" }
node/rpc/Cargo.tomldiffbeforeafterboth--- a/node/rpc/Cargo.toml
+++ b/node/rpc/Cargo.toml
@@ -41,12 +41,12 @@
substrate-frame-rpc-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
tokio = { version = "0.2.25", features = ["macros", "sync"] }
-pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-rpc-core = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-db = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-rpc-core = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-db = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
pallet-nft = { path = "../../pallets/nft" }
uc-rpc = { path = "../../client/rpc" }
pallets/common/Cargo.tomldiffbeforeafterboth--- a/pallets/common/Cargo.toml
+++ b/pallets/common/Cargo.toml
@@ -19,7 +19,7 @@
pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }
evm-coder = { default-features = false, path = '../../crates/evm-coder' }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
serde = { version = "1.0.130", default-features = false }
scale-info = { version = "1.0.0", default-features = false, features = [
"derive",
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -1,6 +1,7 @@
#![cfg_attr(not(feature = "std"), no_std)]
use core::ops::{Deref, DerefMut};
+use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
use sp_std::vec::Vec;
use account::CrossAccountId;
use frame_support::{
@@ -8,6 +9,7 @@
ensure, fail,
traits::{Imbalance, Get, Currency},
};
+use pallet_evm::GasWeightMapping;
use nft_data_structs::{
COLLECTION_NUMBER_LIMIT, Collection, CollectionId, CreateItemData, ExistenceRequirement,
MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_COLLECTION_NAME_LENGTH, MAX_TOKEN_PREFIX_LENGTH,
@@ -27,17 +29,22 @@
pub struct CollectionHandle<T: Config> {
pub id: CollectionId,
collection: Collection<T>,
- pub recorder: pallet_evm_coder_substrate::SubstrateRecorder<T>,
+ pub recorder: SubstrateRecorder<T>,
}
+impl<T: Config> WithRecorder<T> for CollectionHandle<T> {
+ fn recorder(&self) -> &SubstrateRecorder<T> {
+ &self.recorder
+ }
+ fn into_recorder(self) -> SubstrateRecorder<T> {
+ self.recorder
+ }
+}
impl<T: Config> CollectionHandle<T> {
pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {
<CollectionById<T>>::get(id).map(|collection| Self {
id,
collection,
- recorder: pallet_evm_coder_substrate::SubstrateRecorder::new(
- eth::collection_id_to_address(id),
- gas_limit,
- ),
+ recorder: SubstrateRecorder::new(eth::collection_id_to_address(id), gas_limit),
})
}
pub fn new(id: CollectionId) -> Option<Self> {
@@ -46,33 +53,30 @@
pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {
Ok(Self::new(id).ok_or_else(|| <Error<T>>::CollectionNotFound)?)
}
- pub fn log(&self, log: impl evm_coder::ToLog) -> DispatchResult {
- self.recorder.log_sub(log)
+ pub fn log(&self, log: impl evm_coder::ToLog) {
+ self.recorder.log(log)
}
- pub fn log_infallible(&self, log: impl evm_coder::ToLog) {
- self.recorder.log_infallible(log)
+ pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {
+ self.recorder
+ .consume_gas(T::GasWeightMapping::weight_to_gas(
+ <T as frame_system::Config>::DbWeight::get()
+ .read
+ .saturating_mul(reads),
+ ))
}
- #[allow(dead_code)]
- fn consume_gas(&self, gas: u64) -> DispatchResult {
- self.recorder.consume_gas_sub(gas)
- }
- pub fn consume_sload(&self) -> DispatchResult {
- self.recorder.consume_sload_sub()
+ pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {
+ self.recorder
+ .consume_gas(T::GasWeightMapping::weight_to_gas(
+ <T as frame_system::Config>::DbWeight::get()
+ .write
+ .saturating_mul(writes),
+ ))
}
- pub fn consume_sstores(&self, amount: usize) -> DispatchResult {
- self.recorder.consume_sstores_sub(amount)
- }
- pub fn consume_sstore(&self) -> DispatchResult {
- self.recorder.consume_sstore_sub()
- }
- pub fn consume_log(&self, topics: usize, data: usize) -> DispatchResult {
- self.recorder.consume_log_sub(topics, data)
- }
- pub fn submit_logs(self) -> DispatchResult {
+ pub fn submit_logs(self) {
self.recorder.submit_logs()
}
pub fn save(self) -> DispatchResult {
- self.recorder.submit_logs()?;
+ self.recorder.submit_logs();
<CollectionById<T>>::insert(self.id, self.collection);
Ok(())
}
@@ -96,24 +100,20 @@
ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);
Ok(())
}
- pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> Result<bool, DispatchError> {
- self.consume_sload()?;
-
- Ok(*subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject)))
+ pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> bool {
+ *subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject))
}
pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult {
- ensure!(self.is_owner_or_admin(subject)?, <Error<T>>::NoPermission);
+ ensure!(self.is_owner_or_admin(subject), <Error<T>>::NoPermission);
Ok(())
}
- pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> Result<bool, DispatchError> {
- Ok(self.limits.owner_can_transfer() && self.is_owner_or_admin(user)?)
+ pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {
+ self.limits.owner_can_transfer() && self.is_owner_or_admin(user)
}
- pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> Result<bool, DispatchError> {
- Ok(self.limits.owner_can_transfer() && self.is_owner_or_admin(user)?)
+ pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {
+ self.limits.owner_can_transfer() && self.is_owner_or_admin(user)
}
pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {
- self.consume_sload()?;
-
ensure!(
<Allowlist<T>>::get((self.id, user)),
<Error<T>>::AddressNotInAllowlist
pallets/evm-coder-substrate/Cargo.tomldiffbeforeafterboth--- a/pallets/evm-coder-substrate/Cargo.toml
+++ b/pallets/evm-coder-substrate/Cargo.toml
@@ -4,15 +4,18 @@
edition = "2018"
[dependencies]
-scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
+scale-info = { version = "1.0.0", default-features = false, features = [
+ "derive",
+] }
sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
ethereum = { version = "0.9", git = "https://github.com/purestake/ethereum", branch = "joshy-scale-info", default-features = false }
evm-coder = { default-features = false, path = "../../crates/evm-coder" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
+frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
[dependencies.codec]
default-features = false
@@ -31,4 +34,6 @@
"pallet-evm/std",
"frame-support/std",
"frame-system/std",
+ 'frame-benchmarking/std',
]
+runtime-benchmarks = ['frame-benchmarking']
pallets/evm-coder-substrate/src/benchmarking.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/evm-coder-substrate/src/benchmarking.rs
@@ -0,0 +1,8 @@
+use super::*;
+
+use frame_benchmarking::benchmarks;
+
+benchmarks! {
+ // gas_per_second {
+ // }: (pallet_evm::)
+}
pallets/evm-coder-substrate/src/lib.rsdiffbeforeafterboth--- a/pallets/evm-coder-substrate/src/lib.rs
+++ b/pallets/evm-coder-substrate/src/lib.rs
@@ -2,6 +2,8 @@
#[cfg(not(feature = "std"))]
extern crate alloc;
+// #[cfg(feature = "runtime-benchmarks")]
+// pub mod benchmarking;
pub use pallet::*;
@@ -17,7 +19,10 @@
types::{Msg, value},
};
use frame_support::{ensure};
- use pallet_evm::{ExitError, ExitReason, ExitRevert, ExitSucceed, PrecompileOutput};
+ use pallet_evm::{
+ ExitError, ExitReason, ExitRevert, ExitSucceed, PrecompileOutput, GasWeightMapping,
+ };
+ use frame_system::ensure_signed;
pub use frame_support::dispatch::DispatchResult;
use pallet_ethereum::EthereumTransactionSender;
use sp_std::cell::RefCell;
@@ -25,6 +30,7 @@
use sp_core::{H160, H256};
use ethereum::Log;
use frame_support::{pallet_prelude::*, traits::PalletInfo};
+ use frame_system::pallet_prelude::*;
/// DispatchError is opaque, but we need to somehow extract correct error in case of OutOfGas failure
/// So we have this pallet, which defines OutOfGas error, and knews its own id to check if DispatchError
@@ -40,25 +46,24 @@
#[pallet::config]
pub trait Config: frame_system::Config {
type EthereumTransactionSender: pallet_ethereum::EthereumTransactionSender;
+ type GasWeightMapping: pallet_evm::GasWeightMapping;
}
#[pallet::pallet]
pub struct Pallet<T>(_);
- // FIXME: those items are defined as private in evm_gasometer::consts, and we can't directly use it
- pub const G_LOG: u64 = 375;
- pub const G_LOGDATA: u64 = 8;
- pub const G_LOGTOPIC: u64 = 375;
+ #[pallet::call]
+ impl<T: Config> Pallet<T> {
+ #[pallet::weight(0)]
+ pub fn empty_call(origin: OriginFor<T>) -> DispatchResult {
+ let _sender = ensure_signed(origin)?;
+ Ok(())
+ }
+ }
// From instabul hardfork configuration: https://github.com/rust-blockchain/evm/blob/fd4fd6acc0ca3208d6770fdb3ba407c94cdf97c6/runtime/src/lib.rs#L284
pub const G_SLOAD_WORD: u64 = 800;
pub const G_SSTORE_WORD: u64 = 20000;
-
- fn log_price(data: usize, topics: usize) -> u64 {
- G_LOG
- .saturating_add((data as u64).saturating_mul(G_LOGDATA))
- .saturating_add((topics as u64).saturating_mul(G_LOGTOPIC))
- }
pub fn generate_transaction() -> ethereum::TransactionV0 {
use ethereum::{TransactionV0, TransactionAction, TransactionSignature};
@@ -98,16 +103,10 @@
pub fn is_empty(&self) -> bool {
self.logs.borrow().is_empty()
}
- pub fn log_sub(&self, log: impl ToLog) -> DispatchResult {
- self.log_raw_sub(log.to_log(self.contract))
- }
- pub fn log_raw_sub(&self, log: Log) -> DispatchResult {
- self.consume_gas_sub(log_price(log.data.len(), log.topics.len()))?;
- self.logs.borrow_mut().push(log);
- Ok(())
- }
+ // TODO: Replace with real storage in pallet-ethereum,
+ // same way as it is done with frame_system's Events
/// Doesn't consumes any gas, should be used after consume_log_sub
- pub fn log_infallible(&self, log: impl ToLog) {
+ pub fn log(&self, log: impl ToLog) {
self.logs.borrow_mut().push(log.to_log(self.contract));
}
pub fn retrieve_logs(self) -> Vec<Log> {
@@ -125,9 +124,6 @@
}
pub fn consume_sstore_sub(&self) -> DispatchResult {
self.consume_gas_sub(G_SSTORE_WORD)
- }
- pub fn consume_log_sub(&self, topics: usize, data: usize) -> DispatchResult {
- self.consume_gas_sub(log_price(data, topics))
}
pub fn consume_gas_sub(&self, gas: u64) -> DispatchResult {
ensure!(gas != u64::MAX, Error::<T>::OutOfGas);
@@ -154,6 +150,10 @@
*gas_limit -= gas;
Ok(())
}
+ pub fn return_gas(&self, gas: u64) {
+ let mut gas_limit = self.gas_limit.borrow_mut();
+ *gas_limit += gas;
+ }
pub fn evm_to_precompile_output(
self,
@@ -181,12 +181,16 @@
})
}
- pub fn submit_logs(self) -> DispatchResult {
+ pub fn submit_logs(self) {
let logs = self.retrieve_logs();
if logs.is_empty() {
- return Ok(());
+ return;
}
- T::EthereumTransactionSender::submit_logs_transaction(generate_transaction(), logs)
+ T::EthereumTransactionSender::submit_logs_transaction(
+ Default::default(),
+ generate_transaction(),
+ logs,
+ )
}
}
@@ -215,7 +219,31 @@
}
}
- pub fn call_internal<C: evm_coder::Call, E: evm_coder::Callable<C>>(
+ pub trait WithRecorder<T: Config> {
+ fn recorder(&self) -> &SubstrateRecorder<T>;
+ fn into_recorder(self) -> SubstrateRecorder<T>;
+ }
+
+ /// Helper to simplify implementing bridge between evm-coder definitions and pallet-evm
+ pub fn call<
+ T: Config,
+ C: evm_coder::Call + evm_coder::Weighted,
+ E: evm_coder::Callable<C> + WithRecorder<T>,
+ >(
+ caller: H160,
+ mut e: E,
+ value: value,
+ input: &[u8],
+ ) -> Option<PrecompileOutput> {
+ let result = call_internal(caller, &mut e, value, input);
+ e.into_recorder().evm_to_precompile_output(result)
+ }
+
+ fn call_internal<
+ T: Config,
+ C: evm_coder::Call + evm_coder::Weighted,
+ E: evm_coder::Callable<C> + WithRecorder<T>,
+ >(
caller: H160,
e: &mut E,
value: value,
@@ -227,11 +255,28 @@
return Ok(None);
}
let call = call.unwrap();
- e.call(Msg {
+
+ let dispatch_info = call.weight();
+ e.recorder()
+ .consume_gas(T::GasWeightMapping::weight_to_gas(dispatch_info.weight))?;
+
+ match e.call(Msg {
call,
caller,
value,
- })
- .map(Some)
+ }) {
+ Ok(v) => {
+ let unspent = v.post_info.calc_unspent(&dispatch_info);
+ e.recorder()
+ .return_gas(T::GasWeightMapping::weight_to_gas(unspent));
+ Ok(Some(v.data))
+ }
+ Err(v) => {
+ let unspent = v.post_info.calc_unspent(&dispatch_info);
+ e.recorder()
+ .return_gas(T::GasWeightMapping::weight_to_gas(unspent));
+ Err(v.data)
+ }
+ }
}
}
pallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth--- a/pallets/evm-contract-helpers/Cargo.toml
+++ b/pallets/evm-contract-helpers/Cargo.toml
@@ -4,7 +4,9 @@
edition = "2018"
[dependencies]
-scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
+scale-info = { version = "1.0.0", default-features = false, features = [
+ "derive",
+] }
frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
@@ -12,7 +14,7 @@
sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
evm-coder = { default-features = false, path = '../../crates/evm-coder' }
pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
up-sponsorship = { default-features = false, path = '../../primitives/sponsorship' }
log = "0.4.14"
pallets/evm-contract-helpers/exp.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/evm-contract-helpers/exp.rs
@@ -0,0 +1,1474 @@
+#![feature(prelude_import)]
+#[prelude_import]
+use std::prelude::rust_2018::*;
+#[macro_use]
+extern crate std;
+pub use pallet::*;
+pub use eth::*;
+pub mod eth {
+ use core::marker::PhantomData;
+ use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};
+ use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
+ use pallet_evm::{ExitReason, ExitRevert, OnCreate, OnMethodCall, PrecompileOutput};
+ use sp_core::H160;
+ use crate::{
+ AllowlistEnabled, Config, Owner, Pallet, SelfSponsoring, SponsorBasket, SponsoringRateLimit,
+ };
+ use frame_support::traits::Get;
+ use up_sponsorship::SponsorshipHandler;
+ use sp_std::{convert::TryInto, vec::Vec};
+ struct ContractHelpers<T: Config>(SubstrateRecorder<T>);
+ impl<T: Config> WithRecorder<T> for ContractHelpers<T> {
+ fn recorder(&self) -> &SubstrateRecorder<T> {
+ &self.0
+ }
+ fn into_recorder(self) -> SubstrateRecorder<T> {
+ self.0
+ }
+ }
+ impl<T: Config> ContractHelpers<T> {
+ fn contract_owner(&self, contract_address: address) -> Result<address> {
+ Ok(<Owner<T>>::get(contract_address))
+ }
+ fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {
+ Ok(<SelfSponsoring<T>>::get(contract_address))
+ }
+ fn toggle_sponsoring(
+ &mut self,
+ caller: caller,
+ contract_address: address,
+ enabled: bool,
+ ) -> Result<void> {
+ <Pallet<T>>::ensure_owner(contract_address, caller)?;
+ <Pallet<T>>::toggle_sponsoring(contract_address, enabled);
+ Ok(())
+ }
+ fn set_sponsoring_rate_limit(
+ &mut self,
+ caller: caller,
+ contract_address: address,
+ rate_limit: uint32,
+ ) -> Result<void> {
+ <Pallet<T>>::ensure_owner(contract_address, caller)?;
+ <Pallet<T>>::set_sponsoring_rate_limit(contract_address, rate_limit.into());
+ Ok(())
+ }
+ fn get_sponsoring_rate_limit(&self, contract_address: address) -> Result<uint32> {
+ Ok(<SponsoringRateLimit<T>>::get(contract_address)
+ .try_into()
+ .map_err(|_| "rate limit > u32::MAX")?)
+ }
+ fn allowed(&self, contract_address: address, user: address) -> Result<bool> {
+ Ok(<Pallet<T>>::allowed(contract_address, user, true))
+ }
+ fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {
+ Ok(<AllowlistEnabled<T>>::get(contract_address))
+ }
+ fn toggle_allowlist(
+ &mut self,
+ caller: caller,
+ contract_address: address,
+ enabled: bool,
+ ) -> Result<void> {
+ <Pallet<T>>::ensure_owner(contract_address, caller)?;
+ <Pallet<T>>::toggle_allowlist(contract_address, enabled);
+ Ok(())
+ }
+ fn toggle_allowed(
+ &mut self,
+ caller: caller,
+ contract_address: address,
+ user: address,
+ allowed: bool,
+ ) -> Result<void> {
+ <Pallet<T>>::ensure_owner(contract_address, caller)?;
+ <Pallet<T>>::toggle_allowed(contract_address, user, allowed);
+ Ok(())
+ }
+ }
+ pub enum ContractHelpersCall<T: Config> {
+ ERC165Call(::evm_coder::ERC165Call, PhantomData<(T)>),
+ ContractOwner {
+ contract_address: address,
+ },
+ SponsoringEnabled {
+ contract_address: address,
+ },
+ ToggleSponsoring {
+ contract_address: address,
+ enabled: bool,
+ },
+ SetSponsoringRateLimit {
+ contract_address: address,
+ rate_limit: uint32,
+ },
+ GetSponsoringRateLimit {
+ contract_address: address,
+ },
+ Allowed {
+ contract_address: address,
+ user: address,
+ },
+ AllowlistEnabled {
+ contract_address: address,
+ },
+ ToggleAllowlist {
+ contract_address: address,
+ enabled: bool,
+ },
+ ToggleAllowed {
+ contract_address: address,
+ user: address,
+ allowed: bool,
+ },
+ }
+ #[automatically_derived]
+ #[allow(unused_qualifications)]
+ impl<T: ::core::fmt::Debug + Config> ::core::fmt::Debug for ContractHelpersCall<T> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ match (&*self,) {
+ (&ContractHelpersCall::ERC165Call(ref __self_0, ref __self_1),) => {
+ let debug_trait_builder =
+ &mut ::core::fmt::Formatter::debug_tuple(f, "ERC165Call");
+ let _ = ::core::fmt::DebugTuple::field(debug_trait_builder, &&(*__self_0));
+ let _ = ::core::fmt::DebugTuple::field(debug_trait_builder, &&(*__self_1));
+ ::core::fmt::DebugTuple::finish(debug_trait_builder)
+ }
+ (&ContractHelpersCall::ContractOwner {
+ contract_address: ref __self_0,
+ },) => {
+ let debug_trait_builder =
+ &mut ::core::fmt::Formatter::debug_struct(f, "ContractOwner");
+ let _ = ::core::fmt::DebugStruct::field(
+ debug_trait_builder,
+ "contract_address",
+ &&(*__self_0),
+ );
+ ::core::fmt::DebugStruct::finish(debug_trait_builder)
+ }
+ (&ContractHelpersCall::SponsoringEnabled {
+ contract_address: ref __self_0,
+ },) => {
+ let debug_trait_builder =
+ &mut ::core::fmt::Formatter::debug_struct(f, "SponsoringEnabled");
+ let _ = ::core::fmt::DebugStruct::field(
+ debug_trait_builder,
+ "contract_address",
+ &&(*__self_0),
+ );
+ ::core::fmt::DebugStruct::finish(debug_trait_builder)
+ }
+ (&ContractHelpersCall::ToggleSponsoring {
+ contract_address: ref __self_0,
+ enabled: ref __self_1,
+ },) => {
+ let debug_trait_builder =
+ &mut ::core::fmt::Formatter::debug_struct(f, "ToggleSponsoring");
+ let _ = ::core::fmt::DebugStruct::field(
+ debug_trait_builder,
+ "contract_address",
+ &&(*__self_0),
+ );
+ let _ = ::core::fmt::DebugStruct::field(
+ debug_trait_builder,
+ "enabled",
+ &&(*__self_1),
+ );
+ ::core::fmt::DebugStruct::finish(debug_trait_builder)
+ }
+ (&ContractHelpersCall::SetSponsoringRateLimit {
+ contract_address: ref __self_0,
+ rate_limit: ref __self_1,
+ },) => {
+ let debug_trait_builder =
+ &mut ::core::fmt::Formatter::debug_struct(f, "SetSponsoringRateLimit");
+ let _ = ::core::fmt::DebugStruct::field(
+ debug_trait_builder,
+ "contract_address",
+ &&(*__self_0),
+ );
+ let _ = ::core::fmt::DebugStruct::field(
+ debug_trait_builder,
+ "rate_limit",
+ &&(*__self_1),
+ );
+ ::core::fmt::DebugStruct::finish(debug_trait_builder)
+ }
+ (&ContractHelpersCall::GetSponsoringRateLimit {
+ contract_address: ref __self_0,
+ },) => {
+ let debug_trait_builder =
+ &mut ::core::fmt::Formatter::debug_struct(f, "GetSponsoringRateLimit");
+ let _ = ::core::fmt::DebugStruct::field(
+ debug_trait_builder,
+ "contract_address",
+ &&(*__self_0),
+ );
+ ::core::fmt::DebugStruct::finish(debug_trait_builder)
+ }
+ (&ContractHelpersCall::Allowed {
+ contract_address: ref __self_0,
+ user: ref __self_1,
+ },) => {
+ let debug_trait_builder =
+ &mut ::core::fmt::Formatter::debug_struct(f, "Allowed");
+ let _ = ::core::fmt::DebugStruct::field(
+ debug_trait_builder,
+ "contract_address",
+ &&(*__self_0),
+ );
+ let _ =
+ ::core::fmt::DebugStruct::field(debug_trait_builder, "user", &&(*__self_1));
+ ::core::fmt::DebugStruct::finish(debug_trait_builder)
+ }
+ (&ContractHelpersCall::AllowlistEnabled {
+ contract_address: ref __self_0,
+ },) => {
+ let debug_trait_builder =
+ &mut ::core::fmt::Formatter::debug_struct(f, "AllowlistEnabled");
+ let _ = ::core::fmt::DebugStruct::field(
+ debug_trait_builder,
+ "contract_address",
+ &&(*__self_0),
+ );
+ ::core::fmt::DebugStruct::finish(debug_trait_builder)
+ }
+ (&ContractHelpersCall::ToggleAllowlist {
+ contract_address: ref __self_0,
+ enabled: ref __self_1,
+ },) => {
+ let debug_trait_builder =
+ &mut ::core::fmt::Formatter::debug_struct(f, "ToggleAllowlist");
+ let _ = ::core::fmt::DebugStruct::field(
+ debug_trait_builder,
+ "contract_address",
+ &&(*__self_0),
+ );
+ let _ = ::core::fmt::DebugStruct::field(
+ debug_trait_builder,
+ "enabled",
+ &&(*__self_1),
+ );
+ ::core::fmt::DebugStruct::finish(debug_trait_builder)
+ }
+ (&ContractHelpersCall::ToggleAllowed {
+ contract_address: ref __self_0,
+ user: ref __self_1,
+ allowed: ref __self_2,
+ },) => {
+ let debug_trait_builder =
+ &mut ::core::fmt::Formatter::debug_struct(f, "ToggleAllowed");
+ let _ = ::core::fmt::DebugStruct::field(
+ debug_trait_builder,
+ "contract_address",
+ &&(*__self_0),
+ );
+ let _ =
+ ::core::fmt::DebugStruct::field(debug_trait_builder, "user", &&(*__self_1));
+ let _ = ::core::fmt::DebugStruct::field(
+ debug_trait_builder,
+ "allowed",
+ &&(*__self_2),
+ );
+ ::core::fmt::DebugStruct::finish(debug_trait_builder)
+ }
+ }
+ }
+ }
+ impl<T: Config> ContractHelpersCall<T> {
+ #[doc = "contractOwner(address)"]
+ const CONTRACT_OWNER: u32 = 1364373836u32;
+ #[doc = "sponsoringEnabled(address)"]
+ const SPONSORING_ENABLED: u32 = 1613225057u32;
+ #[doc = "toggleSponsoring(address,bool)"]
+ const TOGGLE_SPONSORING: u32 = 4239158662u32;
+ #[doc = "setSponsoringRateLimit(address,uint32)"]
+ const SET_SPONSORING_RATE_LIMIT: u32 = 2008467720u32;
+ #[doc = "getSponsoringRateLimit(address)"]
+ const GET_SPONSORING_RATE_LIMIT: u32 = 1628240573u32;
+ #[doc = "allowed(address,address)"]
+ const ALLOWED: u32 = 1550156133u32;
+ #[doc = "allowlistEnabled(address)"]
+ const ALLOWLIST_ENABLED: u32 = 3346198380u32;
+ #[doc = "toggleAllowlist(address,bool)"]
+ const TOGGLE_ALLOWLIST: u32 = 920527093u32;
+ #[doc = "toggleAllowed(address,address,bool)"]
+ const TOGGLE_ALLOWED: u32 = 1191627804u32;
+ pub const fn interface_id() -> u32 {
+ let mut interface_id = 0;
+ interface_id ^= Self::CONTRACT_OWNER;
+ interface_id ^= Self::SPONSORING_ENABLED;
+ interface_id ^= Self::TOGGLE_SPONSORING;
+ interface_id ^= Self::SET_SPONSORING_RATE_LIMIT;
+ interface_id ^= Self::GET_SPONSORING_RATE_LIMIT;
+ interface_id ^= Self::ALLOWED;
+ interface_id ^= Self::ALLOWLIST_ENABLED;
+ interface_id ^= Self::TOGGLE_ALLOWLIST;
+ interface_id ^= Self::TOGGLE_ALLOWED;
+ interface_id
+ }
+ pub fn supports_interface(interface_id: u32) -> bool {
+ interface_id != 0xffffff
+ && (interface_id == ::evm_coder::ERC165Call::INTERFACE_ID
+ || interface_id == Self::interface_id())
+ }
+ pub fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector, is_impl: bool) {
+ use evm_coder::solidity::*;
+ use core::fmt::Write;
+ let interface = SolidityInterface {
+ name: "ContractHelpers",
+ selector: Self::interface_id(),
+ is: &["Dummy", "ERC165"],
+ functions: (
+ SolidityFunction {
+ docs: &[],
+ selector: "contractOwner(address) 5152b14c",
+ name: "contractOwner",
+ mutability: SolidityMutability::View,
+ args: (<NamedArgument<address>>::new("contractAddress"),),
+ result: <UnnamedArgument<address>>::default(),
+ },
+ SolidityFunction {
+ docs: &[],
+ selector: "sponsoringEnabled(address) 6027dc61",
+ name: "sponsoringEnabled",
+ mutability: SolidityMutability::View,
+ args: (<NamedArgument<address>>::new("contractAddress"),),
+ result: <UnnamedArgument<bool>>::default(),
+ },
+ SolidityFunction {
+ docs: &[],
+ selector: "toggleSponsoring(address,bool) fcac6d86",
+ name: "toggleSponsoring",
+ mutability: SolidityMutability::Mutable,
+ args: (
+ <NamedArgument<address>>::new("contractAddress"),
+ <NamedArgument<bool>>::new("enabled"),
+ ),
+ result: <UnnamedArgument<void>>::default(),
+ },
+ SolidityFunction {
+ docs: &[],
+ selector: "setSponsoringRateLimit(address,uint32) 77b6c908",
+ name: "setSponsoringRateLimit",
+ mutability: SolidityMutability::Mutable,
+ args: (
+ <NamedArgument<address>>::new("contractAddress"),
+ <NamedArgument<uint32>>::new("rateLimit"),
+ ),
+ result: <UnnamedArgument<void>>::default(),
+ },
+ SolidityFunction {
+ docs: &[],
+ selector: "getSponsoringRateLimit(address) 610cfabd",
+ name: "getSponsoringRateLimit",
+ mutability: SolidityMutability::View,
+ args: (<NamedArgument<address>>::new("contractAddress"),),
+ result: <UnnamedArgument<uint32>>::default(),
+ },
+ SolidityFunction {
+ docs: &[],
+ selector: "allowed(address,address) 5c658165",
+ name: "allowed",
+ mutability: SolidityMutability::View,
+ args: (
+ <NamedArgument<address>>::new("contractAddress"),
+ <NamedArgument<address>>::new("user"),
+ ),
+ result: <UnnamedArgument<bool>>::default(),
+ },
+ SolidityFunction {
+ docs: &[],
+ selector: "allowlistEnabled(address) c772ef6c",
+ name: "allowlistEnabled",
+ mutability: SolidityMutability::View,
+ args: (<NamedArgument<address>>::new("contractAddress"),),
+ result: <UnnamedArgument<bool>>::default(),
+ },
+ SolidityFunction {
+ docs: &[],
+ selector: "toggleAllowlist(address,bool) 36de20f5",
+ name: "toggleAllowlist",
+ mutability: SolidityMutability::Mutable,
+ args: (
+ <NamedArgument<address>>::new("contractAddress"),
+ <NamedArgument<bool>>::new("enabled"),
+ ),
+ result: <UnnamedArgument<void>>::default(),
+ },
+ SolidityFunction {
+ docs: &[],
+ selector: "toggleAllowed(address,address,bool) 4706cc1c",
+ name: "toggleAllowed",
+ mutability: SolidityMutability::Mutable,
+ args: (
+ <NamedArgument<address>>::new("contractAddress"),
+ <NamedArgument<address>>::new("user"),
+ <NamedArgument<bool>>::new("allowed"),
+ ),
+ result: <UnnamedArgument<void>>::default(),
+ },
+ ),
+ };
+ if is_impl {
+ tc . collect ("// Common stubs holder\ncontract Dummy {\n\tuint8 dummy;\n\tstring stub_error = \"this contract is implemented in native\";\n}\ncontract ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool) {\n\t\trequire(false, stub_error);\n\t\tinterfaceID;\n\t\treturn true;\n\t}\n}\n" . into ()) ;
+ } else {
+ tc . collect ("// Common stubs holder\ninterface Dummy {\n}\ninterface ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n" . into ()) ;
+ }
+ let mut out = string::new();
+ if "ContractHelpers".starts_with("Inline") {
+ out.push_str("// Inline\n");
+ }
+ let _ = interface.format(is_impl, &mut out, tc);
+ tc.collect(out);
+ }
+ }
+ impl<T: Config> ::evm_coder::Call for ContractHelpersCall<T> {
+ fn parse(
+ method_id: u32,
+ reader: &mut ::evm_coder::abi::AbiReader,
+ ) -> ::evm_coder::execution::Result<Option<Self>> {
+ use ::evm_coder::abi::AbiRead;
+ match method_id {
+ ::evm_coder::ERC165Call::INTERFACE_ID => {
+ return Ok(
+ ::evm_coder::ERC165Call::parse(method_id, reader)?.map(Self::ERC165Call)
+ )
+ }
+ Self::CONTRACT_OWNER => {
+ return Ok(Some(Self::ContractOwner {
+ contract_address: reader.abi_read()?,
+ }))
+ }
+ Self::SPONSORING_ENABLED => {
+ return Ok(Some(Self::SponsoringEnabled {
+ contract_address: reader.abi_read()?,
+ }))
+ }
+ Self::TOGGLE_SPONSORING => {
+ return Ok(Some(Self::ToggleSponsoring {
+ contract_address: reader.abi_read()?,
+ enabled: reader.abi_read()?,
+ }))
+ }
+ Self::SET_SPONSORING_RATE_LIMIT => {
+ return Ok(Some(Self::SetSponsoringRateLimit {
+ contract_address: reader.abi_read()?,
+ rate_limit: reader.abi_read()?,
+ }))
+ }
+ Self::GET_SPONSORING_RATE_LIMIT => {
+ return Ok(Some(Self::GetSponsoringRateLimit {
+ contract_address: reader.abi_read()?,
+ }))
+ }
+ Self::ALLOWED => {
+ return Ok(Some(Self::Allowed {
+ contract_address: reader.abi_read()?,
+ user: reader.abi_read()?,
+ }))
+ }
+ Self::ALLOWLIST_ENABLED => {
+ return Ok(Some(Self::AllowlistEnabled {
+ contract_address: reader.abi_read()?,
+ }))
+ }
+ Self::TOGGLE_ALLOWLIST => {
+ return Ok(Some(Self::ToggleAllowlist {
+ contract_address: reader.abi_read()?,
+ enabled: reader.abi_read()?,
+ }))
+ }
+ Self::TOGGLE_ALLOWED => {
+ return Ok(Some(Self::ToggleAllowed {
+ contract_address: reader.abi_read()?,
+ user: reader.abi_read()?,
+ allowed: reader.abi_read()?,
+ }))
+ }
+ _ => {}
+ }
+ return Ok(None);
+ }
+ }
+ impl<T: Config> ::evm_coder::Weighted for ContractHelpersCall<T> {
+ fn weight(&self) -> ::evm_coder::execution::DispatchInfo {
+ type InternalCall = ContractHelpersCall;
+ match self {
+ InternalCall::ERC165Call(::evm_coder::ERC165Call::SupportsInterface { .. }) => {
+ 100u64.into()
+ }
+ InternalCall::ContractOwner { .. } => ().into(),
+ InternalCall::SponsoringEnabled { .. } => ().into(),
+ InternalCall::ToggleSponsoring { .. } => ().into(),
+ InternalCall::SetSponsoringRateLimit { .. } => ().into(),
+ InternalCall::GetSponsoringRateLimit { .. } => ().into(),
+ InternalCall::Allowed { .. } => ().into(),
+ InternalCall::AllowlistEnabled { .. } => ().into(),
+ InternalCall::ToggleAllowlist { .. } => ().into(),
+ InternalCall::ToggleAllowed { .. } => ().into(),
+ }
+ }
+ }
+ impl<T: Config> ::evm_coder::Callable<ContractHelpersCall<T>> for ContractHelpers<T> {
+ #[allow(unreachable_code)]
+ fn call(
+ &mut self,
+ c: Msg<ContractHelpersCall>,
+ ) -> ::evm_coder::execution::ResultWithPostInfo<::evm_coder::abi::AbiWriter> {
+ use ::evm_coder::abi::AbiWrite;
+ type InternalCall = ContractHelpersCall;
+ match c.call {
+ InternalCall::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {
+ interface_id,
+ }) => {
+ let mut writer = ::evm_coder::abi::AbiWriter::default();
+ writer.bool(&InternalCall::supports_interface(interface_id));
+ return Ok(writer.into());
+ }
+ _ => {}
+ }
+ let mut writer = ::evm_coder::abi::AbiWriter::default();
+ match c.call {
+ InternalCall::ContractOwner { contract_address } => {
+ let result = self.contract_owner(contract_address)?;
+ (&result).into_result()
+ }
+ InternalCall::SponsoringEnabled { contract_address } => {
+ let result = self.sponsoring_enabled(contract_address)?;
+ (&result).into_result()
+ }
+ InternalCall::ToggleSponsoring {
+ contract_address,
+ enabled,
+ } => {
+ let result =
+ self.toggle_sponsoring(c.caller.clone(), contract_address, enabled)?;
+ (&result).into_result()
+ }
+ InternalCall::SetSponsoringRateLimit {
+ contract_address,
+ rate_limit,
+ } => {
+ let result = self.set_sponsoring_rate_limit(
+ c.caller.clone(),
+ contract_address,
+ rate_limit,
+ )?;
+ (&result).into_result()
+ }
+ InternalCall::GetSponsoringRateLimit { contract_address } => {
+ let result = self.get_sponsoring_rate_limit(contract_address)?;
+ (&result).into_result()
+ }
+ InternalCall::Allowed {
+ contract_address,
+ user,
+ } => {
+ let result = self.allowed(contract_address, user)?;
+ (&result).into_result()
+ }
+ InternalCall::AllowlistEnabled { contract_address } => {
+ let result = self.allowlist_enabled(contract_address)?;
+ (&result).into_result()
+ }
+ InternalCall::ToggleAllowlist {
+ contract_address,
+ enabled,
+ } => {
+ let result =
+ self.toggle_allowlist(c.caller.clone(), contract_address, enabled)?;
+ (&result).into_result()
+ }
+ InternalCall::ToggleAllowed {
+ contract_address,
+ user,
+ allowed,
+ } => {
+ let result =
+ self.toggle_allowed(c.caller.clone(), contract_address, user, allowed)?;
+ (&result).into_result()
+ }
+ _ => ::core::panicking::panic("internal error: entered unreachable code"),
+ }
+ }
+ }
+ pub struct HelpersOnMethodCall<T: Config>(PhantomData<*const T>);
+ impl<T: Config> OnMethodCall<T> for HelpersOnMethodCall<T> {
+ fn is_reserved(contract: &sp_core::H160) -> bool {
+ contract == &T::ContractAddress::get()
+ }
+ fn is_used(contract: &sp_core::H160) -> bool {
+ contract == &T::ContractAddress::get()
+ }
+ fn call(
+ source: &sp_core::H160,
+ target: &sp_core::H160,
+ gas_left: u64,
+ input: &[u8],
+ value: sp_core::U256,
+ ) -> Option<PrecompileOutput> {
+ if !<Pallet<T>>::allowed(*target, *source, true) {
+ return Some(PrecompileOutput {
+ exit_status: ExitReason::Revert(ExitRevert::Reverted),
+ cost: 0,
+ output: {
+ let mut writer = AbiWriter::new_call(147028384u32);
+ writer.string("Target contract is allowlisted");
+ writer.finish()
+ },
+ logs: ::alloc::vec::Vec::new(),
+ });
+ }
+ if target != &T::ContractAddress::get() {
+ return None;
+ }
+ let helpers = ContractHelpers::<T>(SubstrateRecorder::<T>::new(*target, gas_left));
+ pallet_evm_coder_substrate::call(*source, helpers, value, input)
+ }
+ fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {
+ (contract == & T :: ContractAddress :: get ()) . then (| | b"`\xe0`@R`&`\x80\x81\x81R\x90a\x04\xf4`\xa09\x80Qa\x00&\x91`\x01\x91` \x90\x91\x01\x90a\x009V[P4\x80\x15a\x003W`\x00\x80\xfd[Pa\x01\rV[\x82\x80Ta\x00E\x90a\x00\xd2V[\x90`\x00R` `\x00 \x90`\x1f\x01` \x90\x04\x81\x01\x92\x82a\x00gW`\x00\x85Ua\x00\xadV[\x82`\x1f\x10a\x00\x80W\x80Q`\xff\x19\x16\x83\x80\x01\x17\x85Ua\x00\xadV[\x82\x80\x01`\x01\x01\x85U\x82\x15a\x00\xadW\x91\x82\x01[\x82\x81\x11\x15a\x00\xadW\x82Q\x82U\x91` \x01\x91\x90`\x01\x01\x90a\x00\x92V[Pa\x00\xb9\x92\x91Pa\x00\xbdV[P\x90V[[\x80\x82\x11\x15a\x00\xb9W`\x00\x81U`\x01\x01a\x00\xbeV[`\x01\x81\x81\x1c\x90\x82\x16\x80a\x00\xe6W`\x7f\x82\x16\x91P[` \x82\x10\x81\x14\x15a\x01\x07WcNH{q`\xe0\x1b`\x00R`\"`\x04R`$`\x00\xfd[P\x91\x90PV[a\x03\xd8\x80a\x01\x1c`\x009`\x00\xf3\xfe`\x80`@R4\x80\x15a\x00\x10W`\x00\x80\xfd[P`\x046\x10a\x00\x9eW`\x005`\xe0\x1c\x80c`\'\xdca\x11a\x00fW\x80c`\'\xdca\x14a\x01\"W\x80ca\x0c\xfa\xbd\x14a\x010W\x80cw\xb6\xc9\x08\x14a\x01SW\x80c\xc7r\xefl\x14a\x01\"W\x80c\xfc\xacm\x86\x14a\x00\xcbW`\x00\x80\xfd[\x80c\x01\xff\xc9\xa7\x14a\x00\xa3W\x80c6\xde \xf5\x14a\x00\xcbW\x80cG\x06\xcc\x1c\x14a\x00\xe0W\x80cQR\xb1L\x14a\x00\xeeW\x80c\\e\x81e\x14a\x01\x14W[`\x00\x80\xfd[a\x00\xb6a\x00\xb16`\x04a\x01\xa2V[a\x01aV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xf3[a\x00\xdea\x00\xd96`\x04a\x01\xffV[a\x01\x87V[\x00[a\x00\xdea\x00\xd96`\x04a\x022V[a\x00\xfca\x00\xb16`\x04a\x02uV[`@Q`\x01`\x01`\xa0\x1b\x03\x90\x91\x16\x81R` \x01a\x00\xc2V[a\x00\xb6a\x00\xb16`\x04a\x02\x90V[a\x00\xb6a\x00\xb16`\x04a\x02uV[a\x01>a\x00\xb16`\x04a\x02uV[`@Qc\xff\xff\xff\xff\x90\x91\x16\x81R` \x01a\x00\xc2V[a\x00\xdea\x00\xd96`\x04a\x02\xbaV[`\x00`\x01`@QbF\x1b\xcd`\xe5\x1b\x81R`\x04\x01a\x01~\x91\x90a\x02\xfaV[`@Q\x80\x91\x03\x90\xfd[`\x01`@QbF\x1b\xcd`\xe5\x1b\x81R`\x04\x01a\x01~\x91\x90a\x02\xfaV[`\x00` \x82\x84\x03\x12\x15a\x01\xb4W`\x00\x80\xfd[\x815`\x01`\x01`\xe0\x1b\x03\x19\x81\x16\x81\x14a\x01\xccW`\x00\x80\xfd[\x93\x92PPPV[\x805`\x01`\x01`\xa0\x1b\x03\x81\x16\x81\x14a\x01\xeaW`\x00\x80\xfd[\x91\x90PV[\x805\x80\x15\x15\x81\x14a\x01\xeaW`\x00\x80\xfd[`\x00\x80`@\x83\x85\x03\x12\x15a\x02\x12W`\x00\x80\xfd[a\x02\x1b\x83a\x01\xd3V[\x91Pa\x02)` \x84\x01a\x01\xefV[\x90P\x92P\x92\x90PV[`\x00\x80`\x00``\x84\x86\x03\x12\x15a\x02GW`\x00\x80\xfd[a\x02P\x84a\x01\xd3V[\x92Pa\x02^` \x85\x01a\x01\xd3V[\x91Pa\x02l`@\x85\x01a\x01\xefV[\x90P\x92P\x92P\x92V[`\x00` \x82\x84\x03\x12\x15a\x02\x87W`\x00\x80\xfd[a\x01\xcc\x82a\x01\xd3V[`\x00\x80`@\x83\x85\x03\x12\x15a\x02\xa3W`\x00\x80\xfd[a\x02\xac\x83a\x01\xd3V[\x91Pa\x02)` \x84\x01a\x01\xd3V[`\x00\x80`@\x83\x85\x03\x12\x15a\x02\xcdW`\x00\x80\xfd[a\x02\xd6\x83a\x01\xd3V[\x91P` \x83\x015c\xff\xff\xff\xff\x81\x16\x81\x14a\x02\xefW`\x00\x80\xfd[\x80\x91PP\x92P\x92\x90PV[`\x00` \x80\x83R`\x00\x84T\x81`\x01\x82\x81\x1c\x91P\x80\x83\x16\x80a\x03\x1cW`\x7f\x83\x16\x92P[\x85\x83\x10\x81\x14\x15a\x03:WcNH{q`\xe0\x1b\x85R`\"`\x04R`$\x85\xfd[\x87\x86\x01\x83\x81R` \x01\x81\x80\x15a\x03WW`\x01\x81\x14a\x03hWa\x03\x93V[`\xff\x19\x86\x16\x82R\x87\x82\x01\x96Pa\x03\x93V[`\x00\x8b\x81R` \x90 `\x00[\x86\x81\x10\x15a\x03\x8dW\x81T\x84\x82\x01R\x90\x85\x01\x90\x89\x01a\x03tV[\x83\x01\x97PP[P\x94\x99\x98PPPPPPPPPV\xfe\xa2dipfsX\"\x12 \xde\xe1\xb0gnP\xa0\xbb\xa7\xaf\xbek+\xe6S6\n\xcd?\x0c+\x81\xebEq\x8c\xe3\xab\xaaC6UdsolcC\x00\x08\t\x003this contract is implemented in native" . to_vec ())
+ }
+ }
+ pub struct HelpersOnCreate<T: Config>(PhantomData<*const T>);
+ impl<T: Config> OnCreate<T> for HelpersOnCreate<T> {
+ fn on_create(owner: H160, contract: H160) {
+ <Owner<T>>::insert(contract, owner);
+ }
+ }
+ pub struct HelpersContractSponsoring<T: Config>(PhantomData<*const T>);
+ impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for HelpersContractSponsoring<T> {
+ fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {
+ if <SelfSponsoring<T>>::get(&call.0) && <Pallet<T>>::allowed(call.0, *who, false) {
+ let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+ if let Some(last_tx_block) = <SponsorBasket<T>>::get(&call.0, who) {
+ let rate_limit = <SponsoringRateLimit<T>>::get(&call.0);
+ let limit_time = last_tx_block + rate_limit;
+ if block_number > limit_time {
+ <SponsorBasket<T>>::insert(&call.0, who, block_number);
+ return Some(call.0);
+ }
+ } else {
+ <SponsorBasket<T>>::insert(&call.0, who, block_number);
+ return Some(call.0);
+ }
+ }
+ None
+ }
+ }
+}
+#[doc = r"
+ The module that hosts all the
+ [FRAME](https://docs.substrate.io/v3/runtime/frame)
+ types needed to add this pallet to a
+ runtime.
+ "]
+pub mod pallet {
+ use evm_coder::execution::Result;
+ use frame_support::pallet_prelude::*;
+ use sp_core::H160;
+ #[doc = r"
+ Configuration trait of this pallet.
+
+ Implement this type for a runtime in order to customize this pallet.
+ "]
+ pub trait Config: frame_system::Config + pallet_evm_coder_substrate::Config {
+ type ContractAddress: Get<H160>;
+ type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;
+ }
+ #[scale_info(skip_type_params(T), capture_docs = "always")]
+ #[doc = r"
+ Custom [dispatch errors](https://docs.substrate.io/v3/runtime/events-and-errors)
+ of this pallet.
+ "]
+ pub enum Error<T> {
+ #[doc(hidden)]
+ #[codec(skip)]
+ __Ignore(
+ frame_support::sp_std::marker::PhantomData<(T)>,
+ frame_support::Never,
+ ),
+ #[doc = " This method is only executable by owner"]
+ NoPermission,
+ }
+ #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
+ const _: () = {
+ impl<T> ::scale_info::TypeInfo for Error<T>
+ where
+ frame_support::sp_std::marker::PhantomData<(T)>: ::scale_info::TypeInfo + 'static,
+ T: 'static,
+ {
+ type Identity = Self;
+ fn type_info() -> ::scale_info::Type {
+ :: scale_info :: Type :: builder () . path (:: scale_info :: Path :: new ("Error" , "pallet_evm_contract_helpers::pallet")) . type_params (< [_] > :: into_vec (box [:: scale_info :: TypeParameter :: new ("T" , :: core :: option :: Option :: None)])) . docs_always (& ["\n\t\t\tCustom [dispatch errors](https://docs.substrate.io/v3/runtime/events-and-errors)\n\t\t\tof this pallet.\n\t\t\t"]) . variant (:: scale_info :: build :: Variants :: new () . variant ("NoPermission" , | v | v . index (0usize as :: core :: primitive :: u8) . docs_always (& ["This method is only executable by owner"])))
+ }
+ };
+ };
+ #[doc = r"
+ The [pallet](https://docs.substrate.io/v3/runtime/frame#pallets) implementing
+ the on-chain logic.
+ "]
+ pub struct Pallet<T>(frame_support::sp_std::marker::PhantomData<(T)>);
+ const _: () = {
+ impl<T> core::clone::Clone for Pallet<T> {
+ fn clone(&self) -> Self {
+ Self(core::clone::Clone::clone(&self.0))
+ }
+ }
+ };
+ const _: () = {
+ impl<T> core::cmp::Eq for Pallet<T> {}
+ };
+ const _: () = {
+ impl<T> core::cmp::PartialEq for Pallet<T> {
+ fn eq(&self, other: &Self) -> bool {
+ true && self.0 == other.0
+ }
+ }
+ };
+ const _: () = {
+ impl<T> core::fmt::Debug for Pallet<T> {
+ fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
+ fmt.debug_tuple("Pallet").field(&self.0).finish()
+ }
+ }
+ };
+ #[allow(type_alias_bounds)]
+ pub(super) type Owner<T: Config> = StorageMap<
+ _GeneratedPrefixForStorageOwner<T>,
+ Twox128,
+ H160,
+ H160,
+ ValueQuery,
+ frame_support::traits::GetDefault,
+ frame_support::traits::GetDefault,
+ >;
+ #[allow(type_alias_bounds)]
+ pub(super) type SelfSponsoring<T: Config> = StorageMap<
+ _GeneratedPrefixForStorageSelfSponsoring<T>,
+ Twox128,
+ H160,
+ bool,
+ ValueQuery,
+ frame_support::traits::GetDefault,
+ frame_support::traits::GetDefault,
+ >;
+ #[allow(type_alias_bounds)]
+ pub(super) type SponsoringRateLimit<T: Config> = StorageMap<
+ _GeneratedPrefixForStorageSponsoringRateLimit<T>,
+ Twox128,
+ H160,
+ T::BlockNumber,
+ ValueQuery,
+ T::DefaultSponsoringRateLimit,
+ frame_support::traits::GetDefault,
+ >;
+ #[allow(type_alias_bounds)]
+ pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<
+ _GeneratedPrefixForStorageSponsorBasket<T>,
+ Twox128,
+ H160,
+ Twox128,
+ H160,
+ T::BlockNumber,
+ OptionQuery,
+ frame_support::traits::GetDefault,
+ frame_support::traits::GetDefault,
+ >;
+ #[allow(type_alias_bounds)]
+ pub(super) type AllowlistEnabled<T: Config> = StorageMap<
+ _GeneratedPrefixForStorageAllowlistEnabled<T>,
+ Twox128,
+ H160,
+ bool,
+ ValueQuery,
+ frame_support::traits::GetDefault,
+ frame_support::traits::GetDefault,
+ >;
+ #[allow(type_alias_bounds)]
+ pub(super) type Allowlist<T: Config> = StorageDoubleMap<
+ _GeneratedPrefixForStorageAllowlist<T>,
+ Twox128,
+ H160,
+ Twox128,
+ H160,
+ bool,
+ ValueQuery,
+ frame_support::traits::GetDefault,
+ frame_support::traits::GetDefault,
+ >;
+ impl<T: Config> Pallet<T> {
+ pub fn toggle_sponsoring(contract: H160, enabled: bool) {
+ <SelfSponsoring<T>>::insert(contract, enabled);
+ }
+ pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {
+ <SponsoringRateLimit<T>>::insert(contract, rate_limit);
+ }
+ #[doc = " Default is returned if allowlist is disabled"]
+ pub fn allowed(contract: H160, user: H160, default: bool) -> bool {
+ if !<AllowlistEnabled<T>>::get(contract) {
+ return default;
+ }
+ <Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user
+ }
+ pub fn toggle_allowlist(contract: H160, enabled: bool) {
+ <AllowlistEnabled<T>>::insert(contract, enabled)
+ }
+ pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {
+ <Allowlist<T>>::insert(contract, user, allowed);
+ }
+ pub fn ensure_owner(contract: H160, user: H160) -> Result<()> {
+ {
+ if !(<Owner<T>>::get(&contract) == user) {
+ {
+ return Err("no permission".into());
+ };
+ }
+ };
+ Ok(())
+ }
+ }
+ impl<T: Config> Pallet<T> {
+ #[doc(hidden)]
+ pub fn pallet_constants_metadata(
+ ) -> frame_support::sp_std::vec::Vec<frame_support::metadata::PalletConstantMetadata>
+ {
+ ::alloc::vec::Vec::new()
+ }
+ }
+ impl<T: Config> Pallet<T> {
+ pub fn error_metadata() -> Option<frame_support::metadata::PalletErrorMetadata> {
+ Some(frame_support::metadata::PalletErrorMetadata {
+ ty: frame_support::scale_info::meta_type::<Error<T>>(),
+ })
+ }
+ }
+ #[doc = r" Type alias to `Pallet`, to be used by `construct_runtime`."]
+ #[doc = r""]
+ #[doc = r" Generated by `pallet` attribute macro."]
+ #[deprecated(note = "use `Pallet` instead")]
+ #[allow(dead_code)]
+ pub type Module<T> = Pallet<T>;
+ impl<T: Config> frame_support::traits::GetStorageVersion for Pallet<T> {
+ fn current_storage_version() -> frame_support::traits::StorageVersion {
+ frame_support::traits::StorageVersion::default()
+ }
+ fn on_chain_storage_version() -> frame_support::traits::StorageVersion {
+ frame_support::traits::StorageVersion::get::<Self>()
+ }
+ }
+ impl<T: Config> frame_support::traits::OnGenesis for Pallet<T> {
+ fn on_genesis() {
+ let storage_version = frame_support::traits::StorageVersion::default();
+ storage_version.put::<Self>();
+ }
+ }
+ impl<T: Config> frame_support::traits::PalletInfoAccess for Pallet<T> {
+ fn index() -> usize {
+ <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::index::<
+ Self,
+ >()
+ .expect(
+ "Pallet is part of the runtime because pallet `Config` trait is \
+ implemented by the runtime",
+ )
+ }
+ fn name() -> &'static str {
+ <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::name::<
+ Self,
+ >()
+ .expect(
+ "Pallet is part of the runtime because pallet `Config` trait is \
+ implemented by the runtime",
+ )
+ }
+ fn module_name() -> &'static str {
+ < < T as frame_system :: Config > :: PalletInfo as frame_support :: traits :: PalletInfo > :: module_name :: < Self > () . expect ("Pallet is part of the runtime because pallet `Config` trait is \
+ implemented by the runtime")
+ }
+ fn crate_version() -> frame_support::traits::CrateVersion {
+ frame_support::traits::CrateVersion {
+ major: 0u16,
+ minor: 1u8,
+ patch: 0u8,
+ }
+ }
+ }
+ impl<T: Config> frame_support::traits::StorageInfoTrait for Pallet<T> {
+ fn storage_info() -> frame_support::sp_std::vec::Vec<frame_support::traits::StorageInfo> {
+ #[allow(unused_mut)]
+ let mut res = ::alloc::vec::Vec::new();
+ {
+ let mut storage_info = < Owner < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ;
+ res.append(&mut storage_info);
+ }
+ {
+ let mut storage_info = < SelfSponsoring < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ;
+ res.append(&mut storage_info);
+ }
+ {
+ let mut storage_info = < SponsoringRateLimit < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ;
+ res.append(&mut storage_info);
+ }
+ {
+ let mut storage_info = < SponsorBasket < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ;
+ res.append(&mut storage_info);
+ }
+ {
+ let mut storage_info = < AllowlistEnabled < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ;
+ res.append(&mut storage_info);
+ }
+ {
+ let mut storage_info = < Allowlist < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ;
+ res.append(&mut storage_info);
+ }
+ res
+ }
+ }
+ #[doc(hidden)]
+ pub mod __substrate_call_check {
+ #[doc(hidden)]
+ pub use __is_call_part_defined_0 as is_call_part_defined;
+ }
+ #[doc = r"Contains one variant per dispatchable that can be called by an extrinsic."]
+ #[codec(encode_bound())]
+ #[codec(decode_bound())]
+ #[scale_info(skip_type_params(T), capture_docs = "always")]
+ #[allow(non_camel_case_types)]
+ pub enum Call<T: Config> {
+ #[doc(hidden)]
+ #[codec(skip)]
+ __Ignore(
+ frame_support::sp_std::marker::PhantomData<(T,)>,
+ frame_support::Never,
+ ),
+ }
+ const _: () = {
+ impl<T: Config> core::fmt::Debug for Call<T> {
+ fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
+ match *self {
+ Self::__Ignore(ref _0, ref _1) => fmt
+ .debug_tuple("Call::__Ignore")
+ .field(&_0)
+ .field(&_1)
+ .finish(),
+ }
+ }
+ }
+ };
+ const _: () = {
+ impl<T: Config> core::clone::Clone for Call<T> {
+ fn clone(&self) -> Self {
+ match self {
+ Self::__Ignore(ref _0, ref _1) => {
+ Self::__Ignore(core::clone::Clone::clone(_0), core::clone::Clone::clone(_1))
+ }
+ }
+ }
+ }
+ };
+ const _: () = {
+ impl<T: Config> core::cmp::Eq for Call<T> {}
+ };
+ const _: () = {
+ impl<T: Config> core::cmp::PartialEq for Call<T> {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (Self::__Ignore(_0, _1), Self::__Ignore(_0_other, _1_other)) => {
+ true && _0 == _0_other && _1 == _1_other
+ }
+ }
+ }
+ }
+ };
+ const _: () = {
+ #[allow(non_camel_case_types)]
+ impl<T: Config> ::codec::Encode for Call<T> {}
+ impl<T: Config> ::codec::EncodeLike for Call<T> {}
+ };
+ const _: () = {
+ #[allow(non_camel_case_types)]
+ impl<T: Config> ::codec::Decode for Call<T> {
+ fn decode<__CodecInputEdqy: ::codec::Input>(
+ __codec_input_edqy: &mut __CodecInputEdqy,
+ ) -> ::core::result::Result<Self, ::codec::Error> {
+ match __codec_input_edqy
+ .read_byte()
+ .map_err(|e| e.chain("Could not decode `Call`, failed to read variant byte"))?
+ {
+ _ => ::core::result::Result::Err(<_ as ::core::convert::Into<_>>::into(
+ "Could not decode `Call`, variant doesn\'t exist",
+ )),
+ }
+ }
+ }
+ };
+ #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
+ const _: () = {
+ impl<T: Config> ::scale_info::TypeInfo for Call<T>
+ where
+ frame_support::sp_std::marker::PhantomData<(T,)>: ::scale_info::TypeInfo + 'static,
+ T: Config + 'static,
+ {
+ type Identity = Self;
+ fn type_info() -> ::scale_info::Type {
+ ::scale_info::Type::builder()
+ .path(::scale_info::Path::new(
+ "Call",
+ "pallet_evm_contract_helpers::pallet",
+ ))
+ .type_params(<[_]>::into_vec(box [::scale_info::TypeParameter::new(
+ "T",
+ ::core::option::Option::None,
+ )]))
+ .docs_always(&[
+ "Contains one variant per dispatchable that can be called by an extrinsic.",
+ ])
+ .variant(::scale_info::build::Variants::new())
+ }
+ };
+ };
+ impl<T: Config> Call<T> {}
+ impl<T: Config> frame_support::dispatch::GetDispatchInfo for Call<T> {
+ fn get_dispatch_info(&self) -> frame_support::dispatch::DispatchInfo {
+ match *self {
+ Self::__Ignore(_, _) => {
+ ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1(
+ &["internal error: entered unreachable code: "],
+ &match (&"__Ignore cannot be used",) {
+ (arg0,) => [::core::fmt::ArgumentV1::new(
+ arg0,
+ ::core::fmt::Display::fmt,
+ )],
+ },
+ ))
+ }
+ }
+ }
+ }
+ impl<T: Config> frame_support::dispatch::GetCallName for Call<T> {
+ fn get_call_name(&self) -> &'static str {
+ match *self {
+ Self::__Ignore(_, _) => {
+ ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1(
+ &["internal error: entered unreachable code: "],
+ &match (&"__PhantomItem cannot be used.",) {
+ (arg0,) => [::core::fmt::ArgumentV1::new(
+ arg0,
+ ::core::fmt::Display::fmt,
+ )],
+ },
+ ))
+ }
+ }
+ }
+ fn get_call_names() -> &'static [&'static str] {
+ &[]
+ }
+ }
+ impl<T: Config> frame_support::traits::UnfilteredDispatchable for Call<T> {
+ type Origin = frame_system::pallet_prelude::OriginFor<T>;
+ fn dispatch_bypass_filter(
+ self,
+ origin: Self::Origin,
+ ) -> frame_support::dispatch::DispatchResultWithPostInfo {
+ match self {
+ Self::__Ignore(_, _) => {
+ let _ = origin;
+ {
+ {
+ ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1(
+ &["internal error: entered unreachable code: "],
+ &match (&"__PhantomItem cannot be used.",) {
+ (arg0,) => [::core::fmt::ArgumentV1::new(
+ arg0,
+ ::core::fmt::Display::fmt,
+ )],
+ },
+ ))
+ }
+ };
+ }
+ }
+ }
+ }
+ impl<T: Config> frame_support::dispatch::Callable<T> for Pallet<T> {
+ type Call = Call<T>;
+ }
+ impl<T: Config> Pallet<T> {
+ #[doc(hidden)]
+ pub fn call_functions() -> frame_support::metadata::PalletCallMetadata {
+ frame_support::scale_info::meta_type::<Call<T>>().into()
+ }
+ }
+ impl<T: Config> frame_support::sp_std::fmt::Debug for Error<T> {
+ fn fmt(
+ &self,
+ f: &mut frame_support::sp_std::fmt::Formatter<'_>,
+ ) -> frame_support::sp_std::fmt::Result {
+ f.write_str(self.as_str())
+ }
+ }
+ impl<T: Config> Error<T> {
+ pub fn as_u8(&self) -> u8 {
+ match &self {
+ Self::__Ignore(_, _) => {
+ ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1(
+ &["internal error: entered unreachable code: "],
+ &match (&"`__Ignore` can never be constructed",) {
+ (arg0,) => [::core::fmt::ArgumentV1::new(
+ arg0,
+ ::core::fmt::Display::fmt,
+ )],
+ },
+ ))
+ }
+ Self::NoPermission => 0usize as u8,
+ }
+ }
+ pub fn as_str(&self) -> &'static str {
+ match &self {
+ Self::__Ignore(_, _) => {
+ ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1(
+ &["internal error: entered unreachable code: "],
+ &match (&"`__Ignore` can never be constructed",) {
+ (arg0,) => [::core::fmt::ArgumentV1::new(
+ arg0,
+ ::core::fmt::Display::fmt,
+ )],
+ },
+ ))
+ }
+ Self::NoPermission => "NoPermission",
+ }
+ }
+ }
+ impl<T: Config> From<Error<T>> for &'static str {
+ fn from(err: Error<T>) -> &'static str {
+ err.as_str()
+ }
+ }
+ impl<T: Config> From<Error<T>> for frame_support::sp_runtime::DispatchError {
+ fn from(err: Error<T>) -> Self {
+ let index = < < T as frame_system :: Config > :: PalletInfo as frame_support :: traits :: PalletInfo > :: index :: < Pallet < T > > () . expect ("Every active module has an index in the runtime; qed") as u8 ;
+ frame_support::sp_runtime::DispatchError::Module {
+ index,
+ error: err.as_u8(),
+ message: Some(err.as_str()),
+ }
+ }
+ }
+ #[doc(hidden)]
+ pub mod __substrate_event_check {
+ #[doc(hidden)]
+ pub use __is_event_part_defined_1 as is_event_part_defined;
+ }
+ impl<T: Config> Pallet<T> {
+ #[doc(hidden)]
+ pub fn storage_metadata() -> frame_support::metadata::PalletStorageMetadata {
+ frame_support :: metadata :: PalletStorageMetadata { prefix : < < T as frame_system :: Config > :: PalletInfo as frame_support :: traits :: PalletInfo > :: name :: < Pallet < T > > () . expect ("Every active pallet has a name in the runtime; qed") , entries : { # [allow (unused_mut)] let mut entries = :: alloc :: vec :: Vec :: new () ; { < Owner < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < SelfSponsoring < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < SponsoringRateLimit < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < SponsorBasket < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < AllowlistEnabled < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < Allowlist < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } entries } , }
+ }
+ }
+ pub(super) struct _GeneratedPrefixForStorageOwner<T>(core::marker::PhantomData<(T,)>);
+ impl<T: Config> frame_support::traits::StorageInstance for _GeneratedPrefixForStorageOwner<T> {
+ fn pallet_prefix() -> &'static str {
+ <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::name::<
+ Pallet<T>,
+ >()
+ .expect("Every active pallet has a name in the runtime; qed")
+ }
+ const STORAGE_PREFIX: &'static str = "Owner";
+ }
+ pub(super) struct _GeneratedPrefixForStorageSelfSponsoring<T>(core::marker::PhantomData<(T,)>);
+ impl<T: Config> frame_support::traits::StorageInstance
+ for _GeneratedPrefixForStorageSelfSponsoring<T>
+ {
+ fn pallet_prefix() -> &'static str {
+ <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::name::<
+ Pallet<T>,
+ >()
+ .expect("Every active pallet has a name in the runtime; qed")
+ }
+ const STORAGE_PREFIX: &'static str = "SelfSponsoring";
+ }
+ pub(super) struct _GeneratedPrefixForStorageSponsoringRateLimit<T>(
+ core::marker::PhantomData<(T,)>,
+ );
+ impl<T: Config> frame_support::traits::StorageInstance
+ for _GeneratedPrefixForStorageSponsoringRateLimit<T>
+ {
+ fn pallet_prefix() -> &'static str {
+ <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::name::<
+ Pallet<T>,
+ >()
+ .expect("Every active pallet has a name in the runtime; qed")
+ }
+ const STORAGE_PREFIX: &'static str = "SponsoringRateLimit";
+ }
+ pub(super) struct _GeneratedPrefixForStorageSponsorBasket<T>(core::marker::PhantomData<(T,)>);
+ impl<T: Config> frame_support::traits::StorageInstance
+ for _GeneratedPrefixForStorageSponsorBasket<T>
+ {
+ fn pallet_prefix() -> &'static str {
+ <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::name::<
+ Pallet<T>,
+ >()
+ .expect("Every active pallet has a name in the runtime; qed")
+ }
+ const STORAGE_PREFIX: &'static str = "SponsorBasket";
+ }
+ pub(super) struct _GeneratedPrefixForStorageAllowlistEnabled<T>(
+ core::marker::PhantomData<(T,)>,
+ );
+ impl<T: Config> frame_support::traits::StorageInstance
+ for _GeneratedPrefixForStorageAllowlistEnabled<T>
+ {
+ fn pallet_prefix() -> &'static str {
+ <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::name::<
+ Pallet<T>,
+ >()
+ .expect("Every active pallet has a name in the runtime; qed")
+ }
+ const STORAGE_PREFIX: &'static str = "AllowlistEnabled";
+ }
+ pub(super) struct _GeneratedPrefixForStorageAllowlist<T>(core::marker::PhantomData<(T,)>);
+ impl<T: Config> frame_support::traits::StorageInstance for _GeneratedPrefixForStorageAllowlist<T> {
+ fn pallet_prefix() -> &'static str {
+ <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::name::<
+ Pallet<T>,
+ >()
+ .expect("Every active pallet has a name in the runtime; qed")
+ }
+ const STORAGE_PREFIX: &'static str = "Allowlist";
+ }
+ #[doc(hidden)]
+ pub mod __substrate_inherent_check {
+ #[doc(hidden)]
+ pub use __is_inherent_part_defined_2 as is_inherent_part_defined;
+ }
+ #[doc = r" Hidden instance generated to be internally used when module is used without"]
+ #[doc = r" instance."]
+ #[doc(hidden)]
+ pub type __InherentHiddenInstance = ();
+ pub(super) trait Store {
+ type Owner;
+ type SelfSponsoring;
+ type SponsoringRateLimit;
+ type SponsorBasket;
+ type AllowlistEnabled;
+ type Allowlist;
+ }
+ impl<T: Config> Store for Pallet<T> {
+ type Owner = Owner<T>;
+ type SelfSponsoring = SelfSponsoring<T>;
+ type SponsoringRateLimit = SponsoringRateLimit<T>;
+ type SponsorBasket = SponsorBasket<T>;
+ type AllowlistEnabled = AllowlistEnabled<T>;
+ type Allowlist = Allowlist<T>;
+ }
+ impl<T: Config> frame_support::traits::Hooks<<T as frame_system::Config>::BlockNumber>
+ for Pallet<T>
+ {
+ }
+ impl<T: Config> frame_support::traits::OnFinalize<<T as frame_system::Config>::BlockNumber>
+ for Pallet<T>
+ {
+ fn on_finalize(n: <T as frame_system::Config>::BlockNumber) {
+ let __within_span__ = {
+ use ::tracing::__macro_support::Callsite as _;
+ static CALLSITE: ::tracing::__macro_support::MacroCallsite = {
+ use ::tracing::__macro_support::MacroCallsite;
+ static META: ::tracing::Metadata<'static> = {
+ ::tracing_core::metadata::Metadata::new(
+ "on_finalize",
+ "pallet_evm_contract_helpers::pallet",
+ ::tracing::Level::TRACE,
+ Some("pallets/evm-contract-helpers/src/lib.rs"),
+ Some(7u32),
+ Some("pallet_evm_contract_helpers::pallet"),
+ ::tracing_core::field::FieldSet::new(
+ &[],
+ ::tracing_core::callsite::Identifier(&CALLSITE),
+ ),
+ ::tracing::metadata::Kind::SPAN,
+ )
+ };
+ MacroCallsite::new(&META)
+ };
+ let mut interest = ::tracing::subscriber::Interest::never();
+ if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
+ && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current()
+ && {
+ interest = CALLSITE.interest();
+ !interest.is_never()
+ }
+ && CALLSITE.is_enabled(interest)
+ {
+ let meta = CALLSITE.metadata();
+ ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) })
+ } else {
+ let span = CALLSITE.disabled_span();
+ {};
+ span
+ }
+ };
+ let __tracing_guard__ = __within_span__.enter();
+ < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: on_finalize (n)
+ }
+ }
+ impl<T: Config> frame_support::traits::OnIdle<<T as frame_system::Config>::BlockNumber>
+ for Pallet<T>
+ {
+ fn on_idle(
+ n: <T as frame_system::Config>::BlockNumber,
+ remaining_weight: frame_support::weights::Weight,
+ ) -> frame_support::weights::Weight {
+ < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: on_idle (n , remaining_weight)
+ }
+ }
+ impl<T: Config> frame_support::traits::OnInitialize<<T as frame_system::Config>::BlockNumber>
+ for Pallet<T>
+ {
+ fn on_initialize(
+ n: <T as frame_system::Config>::BlockNumber,
+ ) -> frame_support::weights::Weight {
+ let __within_span__ = {
+ use ::tracing::__macro_support::Callsite as _;
+ static CALLSITE: ::tracing::__macro_support::MacroCallsite = {
+ use ::tracing::__macro_support::MacroCallsite;
+ static META: ::tracing::Metadata<'static> = {
+ ::tracing_core::metadata::Metadata::new(
+ "on_initialize",
+ "pallet_evm_contract_helpers::pallet",
+ ::tracing::Level::TRACE,
+ Some("pallets/evm-contract-helpers/src/lib.rs"),
+ Some(7u32),
+ Some("pallet_evm_contract_helpers::pallet"),
+ ::tracing_core::field::FieldSet::new(
+ &[],
+ ::tracing_core::callsite::Identifier(&CALLSITE),
+ ),
+ ::tracing::metadata::Kind::SPAN,
+ )
+ };
+ MacroCallsite::new(&META)
+ };
+ let mut interest = ::tracing::subscriber::Interest::never();
+ if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
+ && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current()
+ && {
+ interest = CALLSITE.interest();
+ !interest.is_never()
+ }
+ && CALLSITE.is_enabled(interest)
+ {
+ let meta = CALLSITE.metadata();
+ ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) })
+ } else {
+ let span = CALLSITE.disabled_span();
+ {};
+ span
+ }
+ };
+ let __tracing_guard__ = __within_span__.enter();
+ < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: on_initialize (n)
+ }
+ }
+ impl<T: Config> frame_support::traits::OnRuntimeUpgrade for Pallet<T> {
+ fn on_runtime_upgrade() -> frame_support::weights::Weight {
+ let __within_span__ = {
+ use ::tracing::__macro_support::Callsite as _;
+ static CALLSITE: ::tracing::__macro_support::MacroCallsite = {
+ use ::tracing::__macro_support::MacroCallsite;
+ static META: ::tracing::Metadata<'static> = {
+ ::tracing_core::metadata::Metadata::new(
+ "on_runtime_update",
+ "pallet_evm_contract_helpers::pallet",
+ ::tracing::Level::TRACE,
+ Some("pallets/evm-contract-helpers/src/lib.rs"),
+ Some(7u32),
+ Some("pallet_evm_contract_helpers::pallet"),
+ ::tracing_core::field::FieldSet::new(
+ &[],
+ ::tracing_core::callsite::Identifier(&CALLSITE),
+ ),
+ ::tracing::metadata::Kind::SPAN,
+ )
+ };
+ MacroCallsite::new(&META)
+ };
+ let mut interest = ::tracing::subscriber::Interest::never();
+ if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
+ && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current()
+ && {
+ interest = CALLSITE.interest();
+ !interest.is_never()
+ }
+ && CALLSITE.is_enabled(interest)
+ {
+ let meta = CALLSITE.metadata();
+ ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) })
+ } else {
+ let span = CALLSITE.disabled_span();
+ {};
+ span
+ }
+ };
+ let __tracing_guard__ = __within_span__.enter();
+ let pallet_name = < < T as frame_system :: Config > :: PalletInfo as frame_support :: traits :: PalletInfo > :: name :: < Self > () . unwrap_or ("<unknown pallet name>") ;
+ {
+ let lvl = ::log::Level::Info;
+ if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() {
+ ::log::__private_api_log(
+ ::core::fmt::Arguments::new_v1(
+ &["\u{2705} no migration for "],
+ &match (&pallet_name,) {
+ (arg0,) => [::core::fmt::ArgumentV1::new(
+ arg0,
+ ::core::fmt::Display::fmt,
+ )],
+ },
+ ),
+ lvl,
+ &(
+ frame_support::LOG_TARGET,
+ "pallet_evm_contract_helpers::pallet",
+ "pallets/evm-contract-helpers/src/lib.rs",
+ 7u32,
+ ),
+ );
+ }
+ };
+ < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: on_runtime_upgrade ()
+ }
+ }
+ impl<T: Config> frame_support::traits::OffchainWorker<<T as frame_system::Config>::BlockNumber>
+ for Pallet<T>
+ {
+ fn offchain_worker(n: <T as frame_system::Config>::BlockNumber) {
+ < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: offchain_worker (n)
+ }
+ }
+ impl<T: Config> frame_support::traits::IntegrityTest for Pallet<T> {
+ fn integrity_test() {
+ < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: integrity_test ()
+ }
+ }
+ #[doc(hidden)]
+ pub mod __substrate_genesis_config_check {
+ #[doc(hidden)]
+ pub use __is_genesis_config_defined_3 as is_genesis_config_defined;
+ #[doc(hidden)]
+ pub use __is_std_enabled_for_genesis_3 as is_std_enabled_for_genesis;
+ }
+ #[doc(hidden)]
+ pub mod __substrate_origin_check {
+ #[doc(hidden)]
+ pub use __is_origin_part_defined_4 as is_origin_part_defined;
+ }
+ #[doc(hidden)]
+ pub mod __substrate_validate_unsigned_check {
+ #[doc(hidden)]
+ pub use __is_validate_unsigned_part_defined_5 as is_validate_unsigned_part_defined;
+ }
+}
pallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -1,6 +1,6 @@
use core::marker::PhantomData;
use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};
-use pallet_evm_coder_substrate::SubstrateRecorder;
+use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
use pallet_evm::{ExitReason, ExitRevert, OnCreate, OnMethodCall, PrecompileOutput};
use sp_core::H160;
use crate::{
@@ -11,16 +11,23 @@
use sp_std::{convert::TryInto, vec::Vec};
struct ContractHelpers<T: Config>(SubstrateRecorder<T>);
+impl<T: Config> WithRecorder<T> for ContractHelpers<T> {
+ fn recorder(&self) -> &SubstrateRecorder<T> {
+ &self.0
+ }
+ fn into_recorder(self) -> SubstrateRecorder<T> {
+ self.0
+ }
+}
+
#[solidity_interface(name = "ContractHelpers")]
impl<T: Config> ContractHelpers<T> {
fn contract_owner(&self, contract_address: address) -> Result<address> {
- self.0.consume_sload()?;
Ok(<Owner<T>>::get(contract_address))
}
fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {
- self.0.consume_sload()?;
Ok(<SelfSponsoring<T>>::get(contract_address))
}
@@ -30,9 +37,7 @@
contract_address: address,
enabled: bool,
) -> Result<void> {
- self.0.consume_sload()?;
<Pallet<T>>::ensure_owner(contract_address, caller)?;
- self.0.consume_sstore()?;
<Pallet<T>>::toggle_sponsoring(contract_address, enabled);
Ok(())
}
@@ -43,27 +48,22 @@
contract_address: address,
rate_limit: uint32,
) -> Result<void> {
- self.0.consume_sload()?;
<Pallet<T>>::ensure_owner(contract_address, caller)?;
- self.0.consume_sstore()?;
<Pallet<T>>::set_sponsoring_rate_limit(contract_address, rate_limit.into());
Ok(())
}
fn get_sponsoring_rate_limit(&self, contract_address: address) -> Result<uint32> {
- self.0.consume_sload()?;
Ok(<SponsoringRateLimit<T>>::get(contract_address)
.try_into()
.map_err(|_| "rate limit > u32::MAX")?)
}
fn allowed(&self, contract_address: address, user: address) -> Result<bool> {
- self.0.consume_sload()?;
Ok(<Pallet<T>>::allowed(contract_address, user, true))
}
fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {
- self.0.consume_sload()?;
Ok(<AllowlistEnabled<T>>::get(contract_address))
}
@@ -73,9 +73,7 @@
contract_address: address,
enabled: bool,
) -> Result<void> {
- self.0.consume_sload()?;
<Pallet<T>>::ensure_owner(contract_address, caller)?;
- self.0.consume_sstore()?;
<Pallet<T>>::toggle_allowlist(contract_address, enabled);
Ok(())
}
@@ -87,9 +85,7 @@
user: address,
allowed: bool,
) -> Result<void> {
- self.0.consume_sload()?;
<Pallet<T>>::ensure_owner(contract_address, caller)?;
- self.0.consume_sstore()?;
<Pallet<T>>::toggle_allowed(contract_address, user, allowed);
Ok(())
}
@@ -130,9 +126,8 @@
return None;
}
- let mut helpers = ContractHelpers::<T>(SubstrateRecorder::<T>::new(*target, gas_left));
- let result = pallet_evm_coder_substrate::call_internal(*source, &mut helpers, value, input);
- helpers.0.evm_to_precompile_output(result)
+ let helpers = ContractHelpers::<T>(SubstrateRecorder::<T>::new(*target, gas_left));
+ pallet_evm_coder_substrate::call(*source, helpers, value, input)
}
fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {
@@ -170,5 +165,5 @@
}
}
-generate_stubgen!(contract_helpers_impl, ContractHelpersCall, true);
-generate_stubgen!(contract_helpers_iface, ContractHelpersCall, false);
+generate_stubgen!(contract_helpers_impl, ContractHelpersCall<()>, true);
+generate_stubgen!(contract_helpers_iface, ContractHelpersCall<()>, false);
pallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth--- a/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
+++ b/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
@@ -21,6 +21,7 @@
}
}
+// Selector: 31acb1fe
contract ContractHelpers is Dummy, ERC165 {
// Selector: contractOwner(address) 5152b14c
function contractOwner(address contractAddress)
pallets/evm-migration/Cargo.tomldiffbeforeafterboth--- a/pallets/evm-migration/Cargo.toml
+++ b/pallets/evm-migration/Cargo.toml
@@ -4,7 +4,9 @@
edition = "2018"
[dependencies]
-scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
+scale-info = { version = "1.0.0", default-features = false, features = [
+ "derive",
+] }
frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
@@ -12,8 +14,8 @@
sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
sp-io = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
[dependencies.codec]
default-features = false
pallets/evm-transaction-payment/Cargo.tomldiffbeforeafterboth--- a/pallets/evm-transaction-payment/Cargo.toml
+++ b/pallets/evm-transaction-payment/Cargo.toml
@@ -4,16 +4,18 @@
edition = "2018"
[dependencies]
-scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
+scale-info = { version = "1.0.0", default-features = false, features = [
+ "derive",
+] }
frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
sp-io = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
up-sponsorship = { default-features = false, path = '../../primitives/sponsorship' }
[dependencies.codec]
pallets/fungible/src/erc.rsdiffbeforeafterboth--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -1,15 +1,18 @@
use core::char::{REPLACEMENT_CHARACTER, decode_utf16};
use core::convert::TryInto;
-use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*};
+use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};
use nft_data_structs::CollectionMode;
use pallet_common::erc::CommonEvmHandler;
use sp_core::{H160, U256};
use sp_std::vec::Vec;
use pallet_common::account::CrossAccountId;
use pallet_common::erc::PrecompileOutput;
-use pallet_evm_coder_substrate::{call_internal, dispatch_to_evm};
+use pallet_evm_coder_substrate::{call, dispatch_to_evm};
-use crate::{Allowance, Balance, Config, FungibleHandle, Pallet, TotalSupply};
+use crate::{
+ Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,
+ weights::WeightInfo,
+};
#[derive(ToLog)]
pub enum ERC20Events {
@@ -40,6 +43,7 @@
Ok(string::from_utf8_lossy(&self.token_prefix).into())
}
fn total_supply(&self) -> Result<uint256> {
+ self.consume_store_reads(1)?;
Ok(<TotalSupply<T>>::get(self.id).into())
}
@@ -51,10 +55,12 @@
})
}
fn balance_of(&self, owner: address) -> Result<uint256> {
+ self.consume_store_reads(1)?;
let owner = T::CrossAccountId::from_eth(owner);
let balance = <Balance<T>>::get((self.id, owner));
Ok(balance.into())
}
+ #[weight(<SelfWeightOf<T>>::transfer())]
fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {
let caller = T::CrossAccountId::from_eth(caller);
let to = T::CrossAccountId::from_eth(to);
@@ -63,6 +69,7 @@
<Pallet<T>>::transfer(self, &caller, &to, amount).map_err(|_| "transfer error")?;
Ok(true)
}
+ #[weight(<SelfWeightOf<T>>::transfer_from())]
fn transfer_from(
&mut self,
caller: caller,
@@ -79,6 +86,7 @@
.map_err(dispatch_to_evm::<T>)?;
Ok(true)
}
+ #[weight(<SelfWeightOf<T>>::approve())]
fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {
let caller = T::CrossAccountId::from_eth(caller);
let spender = T::CrossAccountId::from_eth(spender);
@@ -89,6 +97,7 @@
Ok(true)
}
fn allowance(&self, owner: address, spender: address) -> Result<uint256> {
+ self.consume_store_reads(1)?;
let owner = T::CrossAccountId::from_eth(owner);
let spender = T::CrossAccountId::from_eth(spender);
@@ -98,6 +107,7 @@
#[solidity_interface(name = "ERC20UniqueExtensions")]
impl<T: Config> FungibleHandle<T> {
+ #[weight(<SelfWeightOf<T>>::burn_from())]
fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {
let caller = T::CrossAccountId::from_eth(caller);
let from = T::CrossAccountId::from_eth(from);
@@ -111,14 +121,13 @@
#[solidity_interface(name = "UniqueFungible", is(ERC20))]
impl<T: Config> FungibleHandle<T> {}
-generate_stubgen!(gen_impl, UniqueFungibleCall, true);
-generate_stubgen!(gen_iface, UniqueFungibleCall, false);
+generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);
+generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);
impl<T: Config> CommonEvmHandler for FungibleHandle<T> {
const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");
- fn call(mut self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileOutput> {
- let result = call_internal::<UniqueFungibleCall, _>(*source, &mut self, value, input);
- self.0.recorder.evm_to_precompile_output(result)
+ fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileOutput> {
+ call::<T, UniqueFungibleCall<T>, _>(*source, self, value, input)
}
}
pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -6,6 +6,7 @@
use pallet_common::{
Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, account::CrossAccountId,
};
+use pallet_evm_coder_substrate::WithRecorder;
use sp_core::H160;
use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};
@@ -82,6 +83,14 @@
self.0
}
}
+impl<T: Config> WithRecorder<T> for FungibleHandle<T> {
+ fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {
+ self.0.recorder()
+ }
+ fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {
+ self.0.into_recorder()
+ }
+}
impl<T: Config> Deref for FungibleHandle<T> {
type Target = pallet_common::CollectionHandle<T>;
@@ -136,7 +145,7 @@
}
<TotalSupply<T>>::insert(collection.id, total_supply);
- collection.log_infallible(ERC20Events::Transfer {
+ collection.log(ERC20Events::Transfer {
from: *owner.as_eth(),
to: H160::default(),
value: amount.into(),
@@ -179,11 +188,6 @@
} else {
None
};
-
- collection.consume_sstore()?;
- collection.consume_sstore()?;
- collection.consume_log(2, 32)?;
- collection.consume_sstore()?;
// =========
@@ -197,7 +201,7 @@
<Balance<T>>::insert((collection.id, to), balance_to);
}
- collection.log_infallible(ERC20Events::Transfer {
+ collection.log(ERC20Events::Transfer {
from: *from.as_eth(),
to: *to.as_eth(),
value: amount.into(),
@@ -217,8 +221,7 @@
sender: &T::CrossAccountId,
data: Vec<CreateItemData<T>>,
) -> DispatchResult {
- let unrestricted_minting = collection.is_owner_or_admin(sender)?;
- if !unrestricted_minting {
+ if !collection.is_owner_or_admin(sender) {
ensure!(
collection.mint_mode,
<CommonError<T>>::PublicMintingNotAllowed
@@ -241,20 +244,12 @@
.ok_or(ArithmeticError::Overflow)?;
for (user, amount) in data.into_iter() {
- collection.consume_sload()?;
let balance = balances
.entry(user.clone())
.or_insert_with(|| <Balance<T>>::get((collection.id, user)));
*balance = (*balance)
.checked_add(amount)
.ok_or(ArithmeticError::Overflow)?;
- }
-
- collection.consume_sstore()?;
- for _ in &balances {
- collection.consume_sstore()?;
- collection.consume_log(2, 32)?;
- collection.consume_sstore()?;
}
// =========
@@ -263,7 +258,7 @@
for (user, amount) in balances {
<Balance<T>>::insert((collection.id, &user), amount);
- collection.log_infallible(ERC20Events::Transfer {
+ collection.log(ERC20Events::Transfer {
from: H160::default(),
to: *user.as_eth(),
value: amount.into(),
@@ -287,7 +282,7 @@
) {
<Allowance<T>>::insert((collection.id, owner, spender), amount);
- collection.log_infallible(ERC20Events::Approval {
+ collection.log(ERC20Events::Approval {
owner: *owner.as_eth(),
spender: *spender.as_eth(),
value: amount.into(),
@@ -314,7 +309,7 @@
if <Balance<T>>::get((collection.id, owner)) < amount {
ensure!(
- collection.ignores_owned_amount(owner)?,
+ collection.ignores_owned_amount(owner),
<CommonError<T>>::CantApproveMoreThanOwned
);
}
@@ -343,7 +338,7 @@
let allowance = <Allowance<T>>::get((collection.id, from, spender)).checked_sub(amount);
if allowance.is_none() {
ensure!(
- collection.ignores_allowance(spender)?,
+ collection.ignores_allowance(spender),
<CommonError<T>>::TokenValueNotEnough
);
}
@@ -374,7 +369,7 @@
let allowance = <Allowance<T>>::get((collection.id, from, spender)).checked_sub(amount);
if allowance.is_none() {
ensure!(
- collection.ignores_allowance(spender)?,
+ collection.ignores_allowance(spender),
<CommonError<T>>::TokenValueNotEnough
);
}
pallets/nft/Cargo.tomldiffbeforeafterboth--- a/pallets/nft/Cargo.toml
+++ b/pallets/nft/Cargo.toml
@@ -146,9 +146,9 @@
"serde_no_std",
] }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
hex-literal = "0.3.3"
pallet-common = { default-features = false, path = "../common" }
pallets/nft/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/nft/src/benchmarking.rs
+++ b/pallets/nft/src/benchmarking.rs
@@ -155,12 +155,13 @@
let cl = CollectionLimits {
account_token_ownership_limit: Some(0),
- sponsored_data_size: 0,
- token_limit: 1,
- sponsor_transfer_timeout: 0,
- owner_can_destroy: true,
- owner_can_transfer: true,
+ sponsored_data_size: Some(0),
+ token_limit: Some(1),
+ sponsor_transfer_timeout: Some(0),
+ owner_can_destroy: Some(true),
+ owner_can_transfer: Some(true),
sponsored_data_rate_limit: None,
+ transfers_enabled: Some(true),
};
}: set_collection_limits(RawOrigin::Signed(caller.clone()), collection, cl)
pallets/nft/src/dispatch.rsdiffbeforeafterboth--- a/pallets/nft/src/dispatch.rs
+++ b/pallets/nft/src/dispatch.rs
@@ -83,10 +83,6 @@
_ => {}
}
- // TODO: Make submit_logs infallible, but it shouldn't fail here anyway
- dispatched
- .into_inner()
- .submit_logs()
- .expect("should succeed");
+ dispatched.into_inner().submit_logs();
result
}
pallets/nft/src/eth/sponsoring.rsdiffbeforeafterboth--- a/pallets/nft/src/eth/sponsoring.rs
+++ b/pallets/nft/src/eth/sponsoring.rs
@@ -31,7 +31,7 @@
let (method_id, mut reader) = AbiReader::new_call(call).map_err(|_| AnyError)?;
match &collection.mode {
crate::CollectionMode::NFT => {
- let call: UniqueNFTCall = UniqueNFTCall::parse(method_id, &mut reader)
+ let call = <UniqueNFTCall<T>>::parse(method_id, &mut reader)
.map_err(|_| AnyError)?
.ok_or(AnyError)?;
match call {
@@ -63,7 +63,7 @@
}
}
crate::CollectionMode::Fungible(_) => {
- let call: UniqueFungibleCall = UniqueFungibleCall::parse(method_id, &mut reader)
+ let call = <UniqueFungibleCall<T>>::parse(method_id, &mut reader)
.map_err(|_| AnyError)?
.ok_or(AnyError)?;
#[allow(clippy::single_match)]
pallets/nonfungible/src/erc.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -2,18 +2,19 @@
char::{REPLACEMENT_CHARACTER, decode_utf16},
convert::TryInto,
};
-use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*};
+use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
use frame_support::BoundedVec;
use nft_data_structs::TokenId;
use pallet_evm_coder_substrate::dispatch_to_evm;
use sp_core::{H160, U256};
use sp_std::{vec::Vec, vec};
use pallet_common::{account::CrossAccountId, erc::CommonEvmHandler};
-use pallet_evm_coder_substrate::call_internal;
+use pallet_evm_coder_substrate::call;
use pallet_common::erc::PrecompileOutput;
use crate::{
AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,
+ SelfWeightOf, weights::WeightInfo,
};
#[derive(ToLog)]
@@ -64,6 +65,7 @@
/// Returns token's const_metadata
#[solidity(rename_selector = "tokenURI")]
fn token_uri(&self, token_id: uint256) -> Result<string> {
+ self.consume_store_reads(1)?;
let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
Ok(string::from_utf8_lossy(
&<TokenData<T>>::get((self.id, token_id))
@@ -87,6 +89,7 @@
}
fn total_supply(&self) -> Result<uint256> {
+ self.consume_store_reads(1)?;
Ok(<Pallet<T>>::total_supply(self).into())
}
}
@@ -94,11 +97,13 @@
#[solidity_interface(name = "ERC721", events(ERC721Events))]
impl<T: Config> NonfungibleHandle<T> {
fn balance_of(&self, owner: address) -> Result<uint256> {
+ self.consume_store_reads(1)?;
let owner = T::CrossAccountId::from_eth(owner);
let balance = <AccountBalance<T>>::get((self.id, owner));
Ok(balance.into())
}
fn owner_of(&self, token_id: uint256) -> Result<address> {
+ self.consume_store_reads(1)?;
let token: TokenId = token_id.try_into()?;
Ok(*<TokenData<T>>::get((self.id, token))
.ok_or("token not found")?
@@ -129,6 +134,7 @@
Err("not implemented".into())
}
+ #[weight(<SelfWeightOf<T>>::transfer_from())]
fn transfer_from(
&mut self,
caller: caller,
@@ -147,6 +153,7 @@
Ok(())
}
+ #[weight(<SelfWeightOf<T>>::approve())]
fn approve(
&mut self,
caller: caller,
@@ -189,6 +196,7 @@
#[solidity_interface(name = "ERC721Burnable")]
impl<T: Config> NonfungibleHandle<T> {
+ #[weight(<SelfWeightOf<T>>::burn_item())]
fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {
let caller = T::CrossAccountId::from_eth(caller);
let token = token_id.try_into()?;
@@ -206,6 +214,7 @@
/// `token_id` should be obtained with `next_token_id` method,
/// unlike standard, you can't specify it manually
+ #[weight(<SelfWeightOf<T>>::create_item())]
fn mint(&mut self, caller: caller, to: address, token_id: uint256) -> Result<bool> {
let caller = T::CrossAccountId::from_eth(caller);
let to = T::CrossAccountId::from_eth(to);
@@ -235,6 +244,7 @@
/// `token_id` should be obtained with `next_token_id` method,
/// unlike standard, you can't specify it manually
#[solidity(rename_selector = "mintWithTokenURI")]
+ #[weight(<SelfWeightOf<T>>::create_item())]
fn mint_with_token_uri(
&mut self,
caller: caller,
@@ -276,6 +286,7 @@
#[solidity_interface(name = "ERC721UniqueExtensions")]
impl<T: Config> NonfungibleHandle<T> {
+ #[weight(<SelfWeightOf<T>>::transfer())]
fn transfer(
&mut self,
caller: caller,
@@ -291,6 +302,7 @@
Ok(())
}
+ #[weight(<SelfWeightOf<T>>::burn_from())]
fn burn_from(
&mut self,
caller: caller,
@@ -307,12 +319,14 @@
}
fn next_token_id(&self) -> Result<uint256> {
+ self.consume_store_reads(1)?;
Ok(<TokensMinted<T>>::get(self.id)
.checked_add(1)
.ok_or("item id overflow")?
.into())
}
+ #[weight(<SelfWeightOf<T>>::set_variable_metadata(data.len() as u32))]
fn set_variable_metadata(
&mut self,
caller: caller,
@@ -328,6 +342,7 @@
}
fn get_variable_metadata(&self, token_id: uint256) -> Result<bytes> {
+ self.consume_store_reads(1)?;
let token: TokenId = token_id.try_into()?;
Ok(<TokenData<T>>::get((self.id, token))
@@ -335,6 +350,7 @@
.variable_data)
}
+ #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]
fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {
let caller = T::CrossAccountId::from_eth(caller);
let to = T::CrossAccountId::from_eth(to);
@@ -363,6 +379,7 @@
}
#[solidity(rename_selector = "mintBulkWithTokenURI")]
+ #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]
fn mint_bulk_with_token_uri(
&mut self,
caller: caller,
@@ -411,16 +428,13 @@
impl<T: Config> NonfungibleHandle<T> {}
// Not a tests, but code generators
-generate_stubgen!(gen_impl, UniqueNFTCall, true);
-generate_stubgen!(gen_iface, UniqueNFTCall, false);
-
-pub const CODE: &[u8] = include_bytes!("./stubs/UniqueNFT.raw");
+generate_stubgen!(gen_impl, UniqueNFTCall<()>, true);
+generate_stubgen!(gen_iface, UniqueNFTCall<()>, false);
impl<T: Config> CommonEvmHandler for NonfungibleHandle<T> {
const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNFT.raw");
- fn call(mut self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileOutput> {
- let result = call_internal::<UniqueNFTCall, _>(*source, &mut self, value, input);
- self.0.recorder.evm_to_precompile_output(result)
+ fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileOutput> {
+ call::<T, UniqueNFTCall<T>, _>(*source, self, value, input)
}
}
pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -8,6 +8,7 @@
use pallet_common::{
Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, account::CrossAccountId,
};
+use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
use sp_core::H160;
use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
use sp_std::{vec::Vec, vec};
@@ -114,6 +115,14 @@
self.0
}
}
+impl<T: Config> WithRecorder<T> for NonfungibleHandle<T> {
+ fn recorder(&self) -> &SubstrateRecorder<T> {
+ self.0.recorder()
+ }
+ fn into_recorder(self) -> SubstrateRecorder<T> {
+ self.0.into_recorder()
+ }
+}
impl<T: Config> Deref for NonfungibleHandle<T> {
type Target = pallet_common::CollectionHandle<T>;
@@ -164,8 +173,7 @@
.ok_or_else(|| <CommonError<T>>::TokenNotFound)?;
ensure!(
&token_data.owner == sender
- || (collection.limits.owner_can_transfer()
- && collection.is_owner_or_admin(sender)?),
+ || (collection.limits.owner_can_transfer() && collection.is_owner_or_admin(sender)),
<CommonError<T>>::NoPermission
);
@@ -194,7 +202,7 @@
));
}
- collection.log_infallible(ERC721Events::Transfer {
+ collection.log(ERC721Events::Transfer {
from: *token_data.owner.as_eth(),
to: H160::default(),
token_id: token.into(),
@@ -223,8 +231,7 @@
.ok_or_else(|| <CommonError<T>>::TokenNotFound)?;
ensure!(
&token_data.owner == from
- || (collection.limits.owner_can_transfer()
- && collection.is_owner_or_admin(from)?),
+ || (collection.limits.owner_can_transfer() && collection.is_owner_or_admin(from)),
<CommonError<T>>::NoPermission
);
@@ -251,9 +258,6 @@
} else {
None
};
-
- collection.consume_sstores(4)?;
- collection.consume_log(3, 0)?;
// =========
@@ -278,7 +282,7 @@
}
Self::set_allowance_unchecked(collection, from, token, None, true);
- collection.log_infallible(ERC721Events::Transfer {
+ collection.log(ERC721Events::Transfer {
from: *from.as_eth(),
to: *to.as_eth(),
token_id: token.into(),
@@ -298,8 +302,7 @@
sender: &T::CrossAccountId,
data: Vec<CreateItemData<T>>,
) -> DispatchResult {
- let unrestricted_minting = collection.is_owner_or_admin(sender)?;
- if !unrestricted_minting {
+ if !collection.is_owner_or_admin(sender) {
ensure!(
collection.mint_mode,
<CommonError<T>>::PublicMintingNotAllowed
@@ -313,14 +316,6 @@
for data in data.iter() {
<PalletCommon<T>>::ensure_correct_receiver(&data.owner)?;
- if !data.const_data.is_empty() {
- collection.consume_sstore()?;
- }
- if !data.variable_data.is_empty() {
- collection.consume_sstore()?;
- }
- collection.consume_sstore()?;
- collection.consume_log(3, 0)?;
}
let first_token = <TokensMinted<T>>::get(collection.id);
@@ -331,7 +326,6 @@
tokens_minted < collection.limits.token_limit(),
<CommonError<T>>::CollectionTokenLimitExceeded
);
- collection.consume_sstore()?;
let mut balances = BTreeMap::new();
for data in &data {
@@ -345,7 +339,6 @@
<CommonError<T>>::AccountTokenLimitExceeded,
);
}
- collection.consume_sstores(balances.len())?;
// =========
@@ -366,7 +359,7 @@
);
<Owned<T>>::insert((collection.id, &data.owner, token), true);
- collection.log_infallible(ERC721Events::Transfer {
+ collection.log(ERC721Events::Transfer {
from: H160::default(),
to: *data.owner.as_eth(),
token_id: token.into(),
@@ -393,7 +386,7 @@
<Allowance<T>>::insert((collection.id, token), spender);
// In ERC721 there is only one possible approved user of token, so we set
// approved user to spender
- collection.log_infallible(ERC721Events::Approval {
+ collection.log(ERC721Events::Approval {
owner: *sender.as_eth(),
approved: *spender.as_eth(),
token_id: token.into(),
@@ -423,7 +416,7 @@
if !assume_implicit_eth {
// In ERC721 there is only one possible approved user of token, so we set
// approved user to zero address
- collection.log_infallible(ERC721Events::Approval {
+ collection.log(ERC721Events::Approval {
owner: *sender.as_eth(),
approved: H160::default(),
token_id: token.into(),
@@ -463,7 +456,7 @@
<TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;
if &token_data.owner != sender {
ensure!(
- collection.ignores_owned_amount(sender)?,
+ collection.ignores_owned_amount(sender),
<CommonError<T>>::CantApproveMoreThanOwned
);
}
@@ -491,7 +484,7 @@
if <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {
ensure!(
- collection.ignores_allowance(spender)?,
+ collection.ignores_allowance(spender),
<CommonError<T>>::TokenValueNotEnough
);
}
@@ -519,7 +512,7 @@
if <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {
ensure!(
- collection.ignores_allowance(spender)?,
+ collection.ignores_allowance(spender),
<CommonError<T>>::TokenValueNotEnough
);
}
@@ -542,8 +535,6 @@
let token_data =
<TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;
collection.check_can_update_meta(sender, &token_data.owner)?;
-
- collection.consume_sstore()?;
// =========
pallets/refungible/src/common.rsdiffbeforeafterboth--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -58,7 +58,7 @@
}
fn burn_from() -> Weight {
- 0
+ <SelfWeightOf<T>>::burn_from()
}
fn set_variable_metadata(bytes: u32) -> Weight {
pallets/refungible/src/lib.rsdiffbeforeafterboth1#![cfg_attr(not(feature = "std"), no_std)]23use frame_support::{ensure, BoundedVec};4use nft_data_structs::{5 AccessMode, CUSTOM_DATA_LIMIT, Collection, CollectionId, CustomDataLimit,6 MAX_REFUNGIBLE_PIECES, TokenId,7};8use pallet_common::{9 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, account::CrossAccountId,10};11use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};12use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};13use core::ops::Deref;14use codec::{Encode, Decode};15use scale_info::TypeInfo;1617pub use pallet::*;18#[cfg(feature = "runtime-benchmarks")]19pub mod benchmarking;20pub mod common;21pub mod erc;22pub mod weights;23pub struct CreateItemData<T: Config> {24 pub const_data: BoundedVec<u8, CustomDataLimit>,25 pub variable_data: BoundedVec<u8, CustomDataLimit>,26 pub users: BTreeMap<T::CrossAccountId, u128>,27}28pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;2930#[derive(Encode, Decode, Default, TypeInfo)]31pub struct ItemData {32 pub const_data: Vec<u8>,33 pub variable_data: Vec<u8>,34}3536#[frame_support::pallet]37pub mod pallet {38 use super::*;39 use frame_support::{Blake2_128, Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key};40 use nft_data_structs::{CollectionId, TokenId};41 use super::weights::WeightInfo;4243 #[pallet::error]44 pub enum Error<T> {45 /// Not Refungible item data used to mint in Refungible collection.46 NotRefungibleDataUsedToMintFungibleCollectionToken,47 /// Maximum refungibility exceeded48 WrongRefungiblePieces,49 }5051 #[pallet::config]52 pub trait Config: frame_system::Config + pallet_common::Config {53 type WeightInfo: WeightInfo;54 }5556 #[pallet::pallet]57 #[pallet::generate_store(pub(super) trait Store)]58 pub struct Pallet<T>(_);5960 #[pallet::storage]61 pub(super) type TokensMinted<T: Config> =62 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;63 #[pallet::storage]64 pub(super) type TokensBurnt<T: Config> =65 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;6667 #[pallet::storage]68 pub(super) type TokenData<T: Config> = StorageNMap<69 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),70 Value = ItemData,71 QueryKind = ValueQuery,72 >;7374 #[pallet::storage]75 pub(super) type TotalSupply<T: Config> = StorageNMap<76 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),77 Value = u128,78 QueryKind = ValueQuery,79 >;8081 /// Used to enumerate tokens owned by account82 #[pallet::storage]83 pub(super) type Owned<T: Config> = StorageNMap<84 Key = (85 Key<Twox64Concat, CollectionId>,86 Key<Blake2_128Concat, T::CrossAccountId>,87 Key<Twox64Concat, TokenId>,88 ),89 Value = bool,90 QueryKind = ValueQuery,91 >;9293 #[pallet::storage]94 pub(super) type AccountBalance<T: Config> = StorageNMap<95 Key = (96 Key<Twox64Concat, CollectionId>,97 // Owner98 Key<Blake2_128Concat, T::CrossAccountId>,99 ),100 Value = u32,101 QueryKind = ValueQuery,102 >;103104 #[pallet::storage]105 pub(super) type Balance<T: Config> = StorageNMap<106 Key = (107 Key<Twox64Concat, CollectionId>,108 Key<Twox64Concat, TokenId>,109 // Owner110 Key<Blake2_128Concat, T::CrossAccountId>,111 ),112 Value = u128,113 QueryKind = ValueQuery,114 >;115116 #[pallet::storage]117 pub(super) type Allowance<T: Config> = StorageNMap<118 Key = (119 Key<Twox64Concat, CollectionId>,120 Key<Twox64Concat, TokenId>,121 // Owner122 Key<Blake2_128, T::CrossAccountId>,123 // Spender124 Key<Blake2_128Concat, T::CrossAccountId>,125 ),126 Value = u128,127 QueryKind = ValueQuery,128 >;129}130131pub struct RefungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);132impl<T: Config> RefungibleHandle<T> {133 pub fn cast(inner: pallet_common::CollectionHandle<T>) -> Self {134 Self(inner)135 }136 pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {137 self.0138 }139}140impl<T: Config> Deref for RefungibleHandle<T> {141 type Target = pallet_common::CollectionHandle<T>;142143 fn deref(&self) -> &Self::Target {144 &self.0145 }146}147148impl<T: Config> Pallet<T> {149 pub fn total_supply(collection: &RefungibleHandle<T>) -> u32 {150 <TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)151 }152 pub fn token_exists(collection: &RefungibleHandle<T>, token: TokenId) -> bool {153 <TotalSupply<T>>::contains_key((collection.id, token))154 }155}156157// unchecked calls skips any permission checks158impl<T: Config> Pallet<T> {159 pub fn init_collection(data: Collection<T>) -> Result<CollectionId, DispatchError> {160 PalletCommon::init_collection(data)161 }162 pub fn destroy_collection(163 collection: RefungibleHandle<T>,164 sender: &T::CrossAccountId,165 ) -> DispatchResult {166 let id = collection.id;167168 // =========169170 PalletCommon::destroy_collection(collection.0, sender)?;171172 <TokensMinted<T>>::remove(id);173 <TokensBurnt<T>>::remove(id);174 <TokenData<T>>::remove_prefix((id,), None);175 <TotalSupply<T>>::remove_prefix((id,), None);176 <Balance<T>>::remove_prefix((id,), None);177 <Allowance<T>>::remove_prefix((id,), None);178 Ok(())179 }180181 pub fn burn_token(collection: &RefungibleHandle<T>, token_id: TokenId) -> DispatchResult {182 let burnt = <TokensBurnt<T>>::get(collection.id)183 .checked_add(1)184 .ok_or(ArithmeticError::Overflow)?;185186 <TokensBurnt<T>>::insert(collection.id, burnt);187 <TokenData<T>>::remove((collection.id, token_id));188 <TotalSupply<T>>::remove((collection.id, token_id));189 <Balance<T>>::remove_prefix((collection.id, token_id), None);190 <Allowance<T>>::remove_prefix((collection.id, token_id), None);191 // TODO: ERC721 transfer event192 return Ok(());193 }194195 pub fn burn(196 collection: &RefungibleHandle<T>,197 owner: &T::CrossAccountId,198 token: TokenId,199 amount: u128,200 ) -> DispatchResult {201 let total_supply = <TotalSupply<T>>::get((collection.id, token))202 .checked_sub(amount)203 .ok_or(<CommonError<T>>::TokenValueTooLow)?;204205 // This was probally last owner of this token?206 if total_supply == 0 {207 // Ensure user actually owns this amount208 ensure!(209 <Balance<T>>::get((collection.id, token, owner)) == amount,210 <CommonError<T>>::TokenValueTooLow211 );212 let account_balance = <AccountBalance<T>>::get((collection.id, owner))213 .checked_sub(1)214 // Should not occur215 .ok_or(ArithmeticError::Underflow)?;216217 // =========218219 <Owned<T>>::remove((collection.id, owner, token));220 <AccountBalance<T>>::insert((collection.id, owner), account_balance);221 Self::burn_token(collection, token)?;222 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(223 collection.id,224 token,225 owner.clone(),226 amount,227 ));228 return Ok(());229 }230231 let balance = <Balance<T>>::get((collection.id, token, owner))232 .checked_sub(amount)233 .ok_or(<CommonError<T>>::TokenValueTooLow)?;234 let account_balance = if balance == 0 {235 <AccountBalance<T>>::get((collection.id, owner))236 .checked_sub(1)237 // Should not occur238 .ok_or(ArithmeticError::Underflow)?239 } else {240 0241 };242243 // =========244245 if balance == 0 {246 <Owned<T>>::remove((collection.id, owner, token));247 <Balance<T>>::remove((collection.id, token, owner));248 <AccountBalance<T>>::insert((collection.id, owner), account_balance);249 } else {250 <Balance<T>>::insert((collection.id, token, owner), balance);251 }252 <TotalSupply<T>>::insert((collection.id, token), total_supply);253 // TODO: ERC20 transfer event254 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(255 collection.id,256 token,257 owner.clone(),258 amount,259 ));260 Ok(())261 }262263 pub fn transfer(264 collection: &RefungibleHandle<T>,265 from: &T::CrossAccountId,266 to: &T::CrossAccountId,267 token: TokenId,268 amount: u128,269 ) -> DispatchResult {270 ensure!(271 collection.limits.transfers_enabled(),272 <CommonError<T>>::TransferNotAllowed273 );274275 if collection.access == AccessMode::WhiteList {276 collection.check_allowlist(from)?;277 collection.check_allowlist(to)?;278 }279 <PalletCommon<T>>::ensure_correct_receiver(to)?;280281 let balance_from = <Balance<T>>::get((collection.id, token, from))282 .checked_sub(amount)283 .ok_or(<CommonError<T>>::TokenValueTooLow)?;284 let mut create_target = false;285 let from_to_differ = from != to;286 let balance_to = if from != to {287 let old_balance = <Balance<T>>::get((collection.id, token, to));288 if old_balance == 0 {289 create_target = true;290 }291 Some(292 old_balance293 .checked_add(amount)294 .ok_or(ArithmeticError::Overflow)?,295 )296 } else {297 None298 };299300 let account_balance_from = if balance_from == 0 {301 Some(302 <AccountBalance<T>>::get((collection.id, from))303 .checked_sub(1)304 // Should not occur305 .ok_or(ArithmeticError::Underflow)?,306 )307 } else {308 None309 };310 // Account data is created in token, AccountBalance should be increased311 // But only if from != to as we shouldn't check overflow in this case312 let account_balance_to = if create_target && from_to_differ {313 let account_balance_to = <AccountBalance<T>>::get((collection.id, to))314 .checked_add(1)315 .ok_or(ArithmeticError::Overflow)?;316 ensure!(317 account_balance_to < collection.limits.account_token_ownership_limit(),318 <CommonError<T>>::AccountTokenLimitExceeded,319 );320321 Some(account_balance_to)322 } else {323 None324 };325326 // =========327328 if let Some(balance_to) = balance_to {329 // from != to330 if balance_from == 0 {331 <Balance<T>>::remove((collection.id, token, from));332 } else {333 <Balance<T>>::insert((collection.id, token, from), balance_from);334 }335 <Balance<T>>::insert((collection.id, token, to), balance_to);336 if let Some(account_balance_from) = account_balance_from {337 <AccountBalance<T>>::insert((collection.id, from), account_balance_from);338 <Owned<T>>::remove((collection.id, from, token));339 }340 if let Some(account_balance_to) = account_balance_to {341 <AccountBalance<T>>::insert((collection.id, to), account_balance_to);342 <Owned<T>>::insert((collection.id, to, token), true);343 }344 }345346 // TODO: ERC20 transfer event347 <PalletCommon<T>>::deposit_event(CommonEvent::Transfer(348 collection.id,349 token,350 from.clone(),351 to.clone(),352 amount,353 ));354 Ok(())355 }356357 pub fn create_multiple_items(358 collection: &RefungibleHandle<T>,359 sender: &T::CrossAccountId,360 data: Vec<CreateItemData<T>>,361 ) -> DispatchResult {362 let unrestricted_minting = collection.is_owner_or_admin(sender)?;363 if !unrestricted_minting {364 ensure!(365 collection.mint_mode,366 <CommonError<T>>::PublicMintingNotAllowed367 );368 collection.check_allowlist(sender)?;369370 for item in data.iter() {371 for (user, _) in &item.users {372 collection.check_allowlist(&user)?;373 }374 }375 }376377 for item in data.iter() {378 for (owner, _) in item.users.iter() {379 <PalletCommon<T>>::ensure_correct_receiver(owner)?;380 }381 }382383 // Total pieces per tokens384 let totals = data385 .iter()386 .map(|data| {387 Ok(data388 .users389 .iter()390 .map(|u| u.1)391 .try_fold(0u128, |acc, v| acc.checked_add(*v))392 .ok_or(ArithmeticError::Overflow)?)393 })394 .collect::<Result<Vec<_>, DispatchError>>()?;395 for total in &totals {396 ensure!(397 *total <= MAX_REFUNGIBLE_PIECES,398 <Error<T>>::WrongRefungiblePieces399 );400 }401402 let first_token_id = <TokensMinted<T>>::get(collection.id);403 let tokens_minted = first_token_id404 .checked_add(data.len() as u32)405 .ok_or(ArithmeticError::Overflow)?;406 ensure!(407 tokens_minted < collection.limits.token_limit(),408 <CommonError<T>>::CollectionTokenLimitExceeded409 );410411 let mut balances = BTreeMap::new();412 for data in &data {413 for (owner, _) in &data.users {414 let balance = balances415 .entry(owner)416 .or_insert_with(|| <AccountBalance<T>>::get((collection.id, owner)));417 *balance = balance.checked_add(1).ok_or(ArithmeticError::Overflow)?;418419 ensure!(420 *balance <= collection.limits.account_token_ownership_limit(),421 <CommonError<T>>::AccountTokenLimitExceeded,422 );423 }424 }425426 // =========427428 <TokensMinted<T>>::insert(collection.id, tokens_minted);429 for (account, balance) in balances {430 <AccountBalance<T>>::insert((collection.id, account), balance);431 }432 for (i, token) in data.into_iter().enumerate() {433 let token_id = first_token_id + i as u32 + 1;434 <TotalSupply<T>>::insert((collection.id, token_id), totals[i]);435436 <TokenData<T>>::insert(437 (collection.id, token_id),438 ItemData {439 const_data: token.const_data.into(),440 variable_data: token.variable_data.into(),441 },442 );443 for (user, amount) in token.users.into_iter() {444 if amount == 0 {445 continue;446 }447 <Balance<T>>::insert((collection.id, token_id, &user), amount);448 <Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);449 // TODO: ERC20 transfer event450 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(451 collection.id,452 TokenId(token_id),453 user,454 amount,455 ));456 }457 }458 Ok(())459 }460461 pub fn set_allowance_unchecked(462 collection: &RefungibleHandle<T>,463 sender: &T::CrossAccountId,464 spender: &T::CrossAccountId,465 token: TokenId,466 amount: u128,467 ) {468 <Allowance<T>>::insert((collection.id, token, sender, spender), amount);469 // TODO: ERC20 approval event470 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(471 collection.id,472 token,473 sender.clone(),474 spender.clone(),475 amount,476 ))477 }478479 pub fn set_allowance(480 collection: &RefungibleHandle<T>,481 sender: &T::CrossAccountId,482 spender: &T::CrossAccountId,483 token: TokenId,484 amount: u128,485 ) -> DispatchResult {486 if collection.access == AccessMode::WhiteList {487 collection.check_allowlist(&sender)?;488 collection.check_allowlist(&spender)?;489 }490491 <PalletCommon<T>>::ensure_correct_receiver(spender)?;492493 if <Balance<T>>::get((collection.id, token, sender)) < amount {494 ensure!(495 collection.ignores_owned_amount(sender)? && Self::token_exists(collection, token),496 <CommonError<T>>::CantApproveMoreThanOwned497 );498 }499500 // =========501502 Self::set_allowance_unchecked(collection, sender, spender, token, amount);503 Ok(())504 }505506 pub fn transfer_from(507 collection: &RefungibleHandle<T>,508 spender: &T::CrossAccountId,509 from: &T::CrossAccountId,510 to: &T::CrossAccountId,511 token: TokenId,512 amount: u128,513 ) -> DispatchResult {514 if spender.conv_eq(from) {515 return Self::transfer(collection, from, to, token, amount);516 }517 if collection.access == AccessMode::WhiteList {518 // `from`, `to` checked in [`transfer`]519 collection.check_allowlist(spender)?;520 }521522 let allowance =523 <Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);524 if allowance.is_none() {525 ensure!(526 collection.ignores_allowance(spender)?,527 <CommonError<T>>::TokenValueNotEnough528 );529 }530531 // =========532533 Self::transfer(collection, from, to, token, amount)?;534 if let Some(allowance) = allowance {535 Self::set_allowance_unchecked(collection, from, spender, token, allowance);536 }537 Ok(())538 }539540 pub fn burn_from(541 collection: &RefungibleHandle<T>,542 spender: &T::CrossAccountId,543 from: &T::CrossAccountId,544 token: TokenId,545 amount: u128,546 ) -> DispatchResult {547 if spender.conv_eq(from) {548 return Self::burn(collection, from, token, amount);549 }550 if collection.access == AccessMode::WhiteList {551 // `from` checked in [`burn`]552 collection.check_allowlist(spender)?;553 }554555 let allowance =556 <Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);557 if allowance.is_none() {558 ensure!(559 collection.ignores_allowance(spender)?,560 <CommonError<T>>::TokenValueNotEnough561 );562 }563564 // =========565566 Self::burn(collection, from, token, amount)?;567 if let Some(allowance) = allowance {568 Self::set_allowance_unchecked(collection, from, spender, token, allowance);569 }570 Ok(())571 }572573 pub fn set_variable_metadata(574 collection: &RefungibleHandle<T>,575 sender: &T::CrossAccountId,576 token: TokenId,577 data: Vec<u8>,578 ) -> DispatchResult {579 ensure!(580 data.len() as u32 <= CUSTOM_DATA_LIMIT,581 <CommonError<T>>::TokenVariableDataLimitExceeded582 );583 collection.check_can_update_meta(584 sender,585 &T::CrossAccountId::from_sub(collection.owner.clone()),586 )?;587588 collection.consume_sstore()?;589 let token_data = <TokenData<T>>::get((collection.id, token));590591 // =========592593 <TokenData<T>>::insert(594 (collection.id, token),595 ItemData {596 variable_data: data,597 ..token_data598 },599 );600 Ok(())601 }602603 /// Delegated to `create_multiple_items`604 pub fn create_item(605 collection: &RefungibleHandle<T>,606 sender: &T::CrossAccountId,607 data: CreateItemData<T>,608 ) -> DispatchResult {609 Self::create_multiple_items(collection, sender, vec![data])610 }611}1#![cfg_attr(not(feature = "std"), no_std)]23use frame_support::{ensure, BoundedVec};4use nft_data_structs::{5 AccessMode, CUSTOM_DATA_LIMIT, Collection, CollectionId, CustomDataLimit,6 MAX_REFUNGIBLE_PIECES, TokenId,7};8use pallet_common::{9 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, account::CrossAccountId,10};11use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};12use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};13use core::ops::Deref;14use codec::{Encode, Decode};15use scale_info::TypeInfo;1617pub use pallet::*;18#[cfg(feature = "runtime-benchmarks")]19pub mod benchmarking;20pub mod common;21pub mod erc;22pub mod weights;23pub struct CreateItemData<T: Config> {24 pub const_data: BoundedVec<u8, CustomDataLimit>,25 pub variable_data: BoundedVec<u8, CustomDataLimit>,26 pub users: BTreeMap<T::CrossAccountId, u128>,27}28pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;2930#[derive(Encode, Decode, Default, TypeInfo)]31pub struct ItemData {32 pub const_data: Vec<u8>,33 pub variable_data: Vec<u8>,34}3536#[frame_support::pallet]37pub mod pallet {38 use super::*;39 use frame_support::{Blake2_128, Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key};40 use nft_data_structs::{CollectionId, TokenId};41 use super::weights::WeightInfo;4243 #[pallet::error]44 pub enum Error<T> {45 /// Not Refungible item data used to mint in Refungible collection.46 NotRefungibleDataUsedToMintFungibleCollectionToken,47 /// Maximum refungibility exceeded48 WrongRefungiblePieces,49 }5051 #[pallet::config]52 pub trait Config: frame_system::Config + pallet_common::Config {53 type WeightInfo: WeightInfo;54 }5556 #[pallet::pallet]57 #[pallet::generate_store(pub(super) trait Store)]58 pub struct Pallet<T>(_);5960 #[pallet::storage]61 pub(super) type TokensMinted<T: Config> =62 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;63 #[pallet::storage]64 pub(super) type TokensBurnt<T: Config> =65 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;6667 #[pallet::storage]68 pub(super) type TokenData<T: Config> = StorageNMap<69 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),70 Value = ItemData,71 QueryKind = ValueQuery,72 >;7374 #[pallet::storage]75 pub(super) type TotalSupply<T: Config> = StorageNMap<76 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),77 Value = u128,78 QueryKind = ValueQuery,79 >;8081 /// Used to enumerate tokens owned by account82 #[pallet::storage]83 pub(super) type Owned<T: Config> = StorageNMap<84 Key = (85 Key<Twox64Concat, CollectionId>,86 Key<Blake2_128Concat, T::CrossAccountId>,87 Key<Twox64Concat, TokenId>,88 ),89 Value = bool,90 QueryKind = ValueQuery,91 >;9293 #[pallet::storage]94 pub(super) type AccountBalance<T: Config> = StorageNMap<95 Key = (96 Key<Twox64Concat, CollectionId>,97 // Owner98 Key<Blake2_128Concat, T::CrossAccountId>,99 ),100 Value = u32,101 QueryKind = ValueQuery,102 >;103104 #[pallet::storage]105 pub(super) type Balance<T: Config> = StorageNMap<106 Key = (107 Key<Twox64Concat, CollectionId>,108 Key<Twox64Concat, TokenId>,109 // Owner110 Key<Blake2_128Concat, T::CrossAccountId>,111 ),112 Value = u128,113 QueryKind = ValueQuery,114 >;115116 #[pallet::storage]117 pub(super) type Allowance<T: Config> = StorageNMap<118 Key = (119 Key<Twox64Concat, CollectionId>,120 Key<Twox64Concat, TokenId>,121 // Owner122 Key<Blake2_128, T::CrossAccountId>,123 // Spender124 Key<Blake2_128Concat, T::CrossAccountId>,125 ),126 Value = u128,127 QueryKind = ValueQuery,128 >;129}130131pub struct RefungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);132impl<T: Config> RefungibleHandle<T> {133 pub fn cast(inner: pallet_common::CollectionHandle<T>) -> Self {134 Self(inner)135 }136 pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {137 self.0138 }139}140impl<T: Config> Deref for RefungibleHandle<T> {141 type Target = pallet_common::CollectionHandle<T>;142143 fn deref(&self) -> &Self::Target {144 &self.0145 }146}147148impl<T: Config> Pallet<T> {149 pub fn total_supply(collection: &RefungibleHandle<T>) -> u32 {150 <TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)151 }152 pub fn token_exists(collection: &RefungibleHandle<T>, token: TokenId) -> bool {153 <TotalSupply<T>>::contains_key((collection.id, token))154 }155}156157// unchecked calls skips any permission checks158impl<T: Config> Pallet<T> {159 pub fn init_collection(data: Collection<T>) -> Result<CollectionId, DispatchError> {160 PalletCommon::init_collection(data)161 }162 pub fn destroy_collection(163 collection: RefungibleHandle<T>,164 sender: &T::CrossAccountId,165 ) -> DispatchResult {166 let id = collection.id;167168 // =========169170 PalletCommon::destroy_collection(collection.0, sender)?;171172 <TokensMinted<T>>::remove(id);173 <TokensBurnt<T>>::remove(id);174 <TokenData<T>>::remove_prefix((id,), None);175 <TotalSupply<T>>::remove_prefix((id,), None);176 <Balance<T>>::remove_prefix((id,), None);177 <Allowance<T>>::remove_prefix((id,), None);178 Ok(())179 }180181 pub fn burn_token(collection: &RefungibleHandle<T>, token_id: TokenId) -> DispatchResult {182 let burnt = <TokensBurnt<T>>::get(collection.id)183 .checked_add(1)184 .ok_or(ArithmeticError::Overflow)?;185186 <TokensBurnt<T>>::insert(collection.id, burnt);187 <TokenData<T>>::remove((collection.id, token_id));188 <TotalSupply<T>>::remove((collection.id, token_id));189 <Balance<T>>::remove_prefix((collection.id, token_id), None);190 <Allowance<T>>::remove_prefix((collection.id, token_id), None);191 // TODO: ERC721 transfer event192 return Ok(());193 }194195 pub fn burn(196 collection: &RefungibleHandle<T>,197 owner: &T::CrossAccountId,198 token: TokenId,199 amount: u128,200 ) -> DispatchResult {201 let total_supply = <TotalSupply<T>>::get((collection.id, token))202 .checked_sub(amount)203 .ok_or(<CommonError<T>>::TokenValueTooLow)?;204205 // This was probally last owner of this token?206 if total_supply == 0 {207 // Ensure user actually owns this amount208 ensure!(209 <Balance<T>>::get((collection.id, token, owner)) == amount,210 <CommonError<T>>::TokenValueTooLow211 );212 let account_balance = <AccountBalance<T>>::get((collection.id, owner))213 .checked_sub(1)214 // Should not occur215 .ok_or(ArithmeticError::Underflow)?;216217 // =========218219 <Owned<T>>::remove((collection.id, owner, token));220 <AccountBalance<T>>::insert((collection.id, owner), account_balance);221 Self::burn_token(collection, token)?;222 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(223 collection.id,224 token,225 owner.clone(),226 amount,227 ));228 return Ok(());229 }230231 let balance = <Balance<T>>::get((collection.id, token, owner))232 .checked_sub(amount)233 .ok_or(<CommonError<T>>::TokenValueTooLow)?;234 let account_balance = if balance == 0 {235 <AccountBalance<T>>::get((collection.id, owner))236 .checked_sub(1)237 // Should not occur238 .ok_or(ArithmeticError::Underflow)?239 } else {240 0241 };242243 // =========244245 if balance == 0 {246 <Owned<T>>::remove((collection.id, owner, token));247 <Balance<T>>::remove((collection.id, token, owner));248 <AccountBalance<T>>::insert((collection.id, owner), account_balance);249 } else {250 <Balance<T>>::insert((collection.id, token, owner), balance);251 }252 <TotalSupply<T>>::insert((collection.id, token), total_supply);253 // TODO: ERC20 transfer event254 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(255 collection.id,256 token,257 owner.clone(),258 amount,259 ));260 Ok(())261 }262263 pub fn transfer(264 collection: &RefungibleHandle<T>,265 from: &T::CrossAccountId,266 to: &T::CrossAccountId,267 token: TokenId,268 amount: u128,269 ) -> DispatchResult {270 ensure!(271 collection.limits.transfers_enabled(),272 <CommonError<T>>::TransferNotAllowed273 );274275 if collection.access == AccessMode::WhiteList {276 collection.check_allowlist(from)?;277 collection.check_allowlist(to)?;278 }279 <PalletCommon<T>>::ensure_correct_receiver(to)?;280281 let balance_from = <Balance<T>>::get((collection.id, token, from))282 .checked_sub(amount)283 .ok_or(<CommonError<T>>::TokenValueTooLow)?;284 let mut create_target = false;285 let from_to_differ = from != to;286 let balance_to = if from != to {287 let old_balance = <Balance<T>>::get((collection.id, token, to));288 if old_balance == 0 {289 create_target = true;290 }291 Some(292 old_balance293 .checked_add(amount)294 .ok_or(ArithmeticError::Overflow)?,295 )296 } else {297 None298 };299300 let account_balance_from = if balance_from == 0 {301 Some(302 <AccountBalance<T>>::get((collection.id, from))303 .checked_sub(1)304 // Should not occur305 .ok_or(ArithmeticError::Underflow)?,306 )307 } else {308 None309 };310 // Account data is created in token, AccountBalance should be increased311 // But only if from != to as we shouldn't check overflow in this case312 let account_balance_to = if create_target && from_to_differ {313 let account_balance_to = <AccountBalance<T>>::get((collection.id, to))314 .checked_add(1)315 .ok_or(ArithmeticError::Overflow)?;316 ensure!(317 account_balance_to < collection.limits.account_token_ownership_limit(),318 <CommonError<T>>::AccountTokenLimitExceeded,319 );320321 Some(account_balance_to)322 } else {323 None324 };325326 // =========327328 if let Some(balance_to) = balance_to {329 // from != to330 if balance_from == 0 {331 <Balance<T>>::remove((collection.id, token, from));332 } else {333 <Balance<T>>::insert((collection.id, token, from), balance_from);334 }335 <Balance<T>>::insert((collection.id, token, to), balance_to);336 if let Some(account_balance_from) = account_balance_from {337 <AccountBalance<T>>::insert((collection.id, from), account_balance_from);338 <Owned<T>>::remove((collection.id, from, token));339 }340 if let Some(account_balance_to) = account_balance_to {341 <AccountBalance<T>>::insert((collection.id, to), account_balance_to);342 <Owned<T>>::insert((collection.id, to, token), true);343 }344 }345346 // TODO: ERC20 transfer event347 <PalletCommon<T>>::deposit_event(CommonEvent::Transfer(348 collection.id,349 token,350 from.clone(),351 to.clone(),352 amount,353 ));354 Ok(())355 }356357 pub fn create_multiple_items(358 collection: &RefungibleHandle<T>,359 sender: &T::CrossAccountId,360 data: Vec<CreateItemData<T>>,361 ) -> DispatchResult {362 if !collection.is_owner_or_admin(sender) {363 ensure!(364 collection.mint_mode,365 <CommonError<T>>::PublicMintingNotAllowed366 );367 collection.check_allowlist(sender)?;368369 for item in data.iter() {370 for (user, _) in &item.users {371 collection.check_allowlist(&user)?;372 }373 }374 }375376 for item in data.iter() {377 for (owner, _) in item.users.iter() {378 <PalletCommon<T>>::ensure_correct_receiver(owner)?;379 }380 }381382 // Total pieces per tokens383 let totals = data384 .iter()385 .map(|data| {386 Ok(data387 .users388 .iter()389 .map(|u| u.1)390 .try_fold(0u128, |acc, v| acc.checked_add(*v))391 .ok_or(ArithmeticError::Overflow)?)392 })393 .collect::<Result<Vec<_>, DispatchError>>()?;394 for total in &totals {395 ensure!(396 *total <= MAX_REFUNGIBLE_PIECES,397 <Error<T>>::WrongRefungiblePieces398 );399 }400401 let first_token_id = <TokensMinted<T>>::get(collection.id);402 let tokens_minted = first_token_id403 .checked_add(data.len() as u32)404 .ok_or(ArithmeticError::Overflow)?;405 ensure!(406 tokens_minted < collection.limits.token_limit(),407 <CommonError<T>>::CollectionTokenLimitExceeded408 );409410 let mut balances = BTreeMap::new();411 for data in &data {412 for (owner, _) in &data.users {413 let balance = balances414 .entry(owner)415 .or_insert_with(|| <AccountBalance<T>>::get((collection.id, owner)));416 *balance = balance.checked_add(1).ok_or(ArithmeticError::Overflow)?;417418 ensure!(419 *balance <= collection.limits.account_token_ownership_limit(),420 <CommonError<T>>::AccountTokenLimitExceeded,421 );422 }423 }424425 // =========426427 <TokensMinted<T>>::insert(collection.id, tokens_minted);428 for (account, balance) in balances {429 <AccountBalance<T>>::insert((collection.id, account), balance);430 }431 for (i, token) in data.into_iter().enumerate() {432 let token_id = first_token_id + i as u32 + 1;433 <TotalSupply<T>>::insert((collection.id, token_id), totals[i]);434435 <TokenData<T>>::insert(436 (collection.id, token_id),437 ItemData {438 const_data: token.const_data.into(),439 variable_data: token.variable_data.into(),440 },441 );442 for (user, amount) in token.users.into_iter() {443 if amount == 0 {444 continue;445 }446 <Balance<T>>::insert((collection.id, token_id, &user), amount);447 <Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);448 // TODO: ERC20 transfer event449 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(450 collection.id,451 TokenId(token_id),452 user,453 amount,454 ));455 }456 }457 Ok(())458 }459460 pub fn set_allowance_unchecked(461 collection: &RefungibleHandle<T>,462 sender: &T::CrossAccountId,463 spender: &T::CrossAccountId,464 token: TokenId,465 amount: u128,466 ) {467 <Allowance<T>>::insert((collection.id, token, sender, spender), amount);468 // TODO: ERC20 approval event469 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(470 collection.id,471 token,472 sender.clone(),473 spender.clone(),474 amount,475 ))476 }477478 pub fn set_allowance(479 collection: &RefungibleHandle<T>,480 sender: &T::CrossAccountId,481 spender: &T::CrossAccountId,482 token: TokenId,483 amount: u128,484 ) -> DispatchResult {485 if collection.access == AccessMode::WhiteList {486 collection.check_allowlist(&sender)?;487 collection.check_allowlist(&spender)?;488 }489490 <PalletCommon<T>>::ensure_correct_receiver(spender)?;491492 if <Balance<T>>::get((collection.id, token, sender)) < amount {493 ensure!(494 collection.ignores_owned_amount(sender) && Self::token_exists(collection, token),495 <CommonError<T>>::CantApproveMoreThanOwned496 );497 }498499 // =========500501 Self::set_allowance_unchecked(collection, sender, spender, token, amount);502 Ok(())503 }504505 pub fn transfer_from(506 collection: &RefungibleHandle<T>,507 spender: &T::CrossAccountId,508 from: &T::CrossAccountId,509 to: &T::CrossAccountId,510 token: TokenId,511 amount: u128,512 ) -> DispatchResult {513 if spender.conv_eq(from) {514 return Self::transfer(collection, from, to, token, amount);515 }516 if collection.access == AccessMode::WhiteList {517 // `from`, `to` checked in [`transfer`]518 collection.check_allowlist(spender)?;519 }520521 let allowance =522 <Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);523 if allowance.is_none() {524 ensure!(525 collection.ignores_allowance(spender),526 <CommonError<T>>::TokenValueNotEnough527 );528 }529530 // =========531532 Self::transfer(collection, from, to, token, amount)?;533 if let Some(allowance) = allowance {534 Self::set_allowance_unchecked(collection, from, spender, token, allowance);535 }536 Ok(())537 }538539 pub fn burn_from(540 collection: &RefungibleHandle<T>,541 spender: &T::CrossAccountId,542 from: &T::CrossAccountId,543 token: TokenId,544 amount: u128,545 ) -> DispatchResult {546 if spender.conv_eq(from) {547 return Self::burn(collection, from, token, amount);548 }549 if collection.access == AccessMode::WhiteList {550 // `from` checked in [`burn`]551 collection.check_allowlist(spender)?;552 }553554 let allowance =555 <Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);556 if allowance.is_none() {557 ensure!(558 collection.ignores_allowance(spender),559 <CommonError<T>>::TokenValueNotEnough560 );561 }562563 // =========564565 Self::burn(collection, from, token, amount)?;566 if let Some(allowance) = allowance {567 Self::set_allowance_unchecked(collection, from, spender, token, allowance);568 }569 Ok(())570 }571572 pub fn set_variable_metadata(573 collection: &RefungibleHandle<T>,574 sender: &T::CrossAccountId,575 token: TokenId,576 data: Vec<u8>,577 ) -> DispatchResult {578 ensure!(579 data.len() as u32 <= CUSTOM_DATA_LIMIT,580 <CommonError<T>>::TokenVariableDataLimitExceeded581 );582 collection.check_can_update_meta(583 sender,584 &T::CrossAccountId::from_sub(collection.owner.clone()),585 )?;586587 let token_data = <TokenData<T>>::get((collection.id, token));588589 // =========590591 <TokenData<T>>::insert(592 (collection.id, token),593 ItemData {594 variable_data: data,595 ..token_data596 },597 );598 Ok(())599 }600601 /// Delegated to `create_multiple_items`602 pub fn create_item(603 collection: &RefungibleHandle<T>,604 sender: &T::CrossAccountId,605 data: CreateItemData<T>,606 ) -> DispatchResult {607 Self::create_multiple_items(collection, sender, vec![data])608 }609}runtime/Cargo.tomldiffbeforeafterboth--- a/runtime/Cargo.toml
+++ b/runtime/Cargo.toml
@@ -387,10 +387,10 @@
pallet-evm-transaction-payment = { path = '../pallets/evm-transaction-payment', default-features = false }
pallet-evm-coder-substrate = { default-features = false, path = "../pallets/evm-coder-substrate" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
################################################################################
# Build Dependencies
runtime/src/lib.rsdiffbeforeafterboth--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -66,7 +66,7 @@
};
use smallvec::smallvec;
use codec::{Encode, Decode};
-use pallet_evm::{Account as EVMAccount, FeeCalculator, OnMethodCall};
+use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping, OnMethodCall};
use fp_rpc::TransactionStatus;
use sp_core::crypto::Public;
use sp_runtime::{
@@ -247,10 +247,37 @@
}
}
+// Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case
+// (contract, which only writes a lot of data),
+// approximating on top of our real store write weight
+parameter_types! {
+ pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND / <Runtime as frame_system::Config>::DbWeight::get().write;
+ pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000;
+ pub const WeightPerGas: u64 = WEIGHT_PER_SECOND / GasPerSecond::get();
+}
+
+/// Limiting EVM execution to 50% of block for substrate users and management tasks
+/// EVM transaction consumes more weight than substrate's, so we can't rely on them being
+/// scheduled fairly
+const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);
+parameter_types! {
+ pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get());
+}
+
+pub enum FixedGasWeightMapping {}
+impl GasWeightMapping for FixedGasWeightMapping {
+ fn gas_to_weight(gas: u64) -> Weight {
+ gas.saturating_mul(WeightPerGas::get())
+ }
+ fn weight_to_gas(weight: Weight) -> u64 {
+ weight / WeightPerGas::get()
+ }
+}
+
impl pallet_evm::Config for Runtime {
type BlockGasLimit = BlockGasLimit;
type FeeCalculator = FixedFee;
- type GasWeightMapping = ();
+ type GasWeightMapping = FixedGasWeightMapping;
type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
type CallOrigin = EnsureAddressTruncated;
type WithdrawOrigin = EnsureAddressTruncated;
@@ -289,14 +316,9 @@
}
}
-parameter_types! {
- pub BlockGasLimit: U256 = U256::from(u32::max_value());
-}
-
impl pallet_ethereum::Config for Runtime {
type Event = Event;
type StateRoot = pallet_ethereum::IntermediateStateRoot;
- type EvmSubmitLog = pallet_evm::Pallet<Self>;
}
impl pallet_randomness_collective_flip::Config for Runtime {}
@@ -671,6 +693,7 @@
impl pallet_evm_coder_substrate::Config for Runtime {
type EthereumTransactionSender = pallet_ethereum::Pallet<Self>;
+ type GasWeightMapping = FixedGasWeightMapping;
}
impl pallet_xcm::Config for Runtime {