difftreelog
misk: Remove some warnings. Add over_max_size test
in: master
12 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2347,6 +2347,7 @@
"sha3-const",
"similar-asserts",
"sp-std",
+ "trybuild",
]
[[package]]
@@ -12671,6 +12672,21 @@
]
[[package]]
+name = "trybuild"
+version = "1.0.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea496675d71016e9bc76aa42d87f16aefd95447cc5818e671e12b2d7e269075d"
+dependencies = [
+ "glob",
+ "once_cell",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "termcolor",
+ "toml",
+]
+
+[[package]]
name = "tt-call"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
crates/evm-coder/Cargo.tomldiffbeforeafterboth--- a/crates/evm-coder/Cargo.toml
+++ b/crates/evm-coder/Cargo.toml
@@ -29,6 +29,7 @@
hex-literal = "0.3.4"
similar-asserts = "1.4.2"
concat-idents = "1.1.3"
+trybuild = "1.0"
[features]
default = ["std"]
crates/evm-coder/src/custom_signature.rsdiffbeforeafterboth--- a/crates/evm-coder/src/custom_signature.rs
+++ b/crates/evm-coder/src/custom_signature.rs
@@ -423,15 +423,6 @@
assert_eq!(<MaxSize>::name(), "!".repeat(SIGNATURE_SIZE_LIMIT));
}
- // This test must NOT compile with "index out of bounds"!
- // #[test]
- // fn over_max_size() {
- // assert_eq!(
- // <Vec<MaxSize>>::name(),
- // "!".repeat(SIGNATURE_SIZE_LIMIT) + "[]"
- // );
- // }
-
#[test]
fn make_func_without_args() {
const SIG: FunctionSignature = make_signature!(
@@ -498,4 +489,10 @@
fn shift() {
assert_eq!(<(u32,)>::name(), "(uint32)");
}
+
+ #[test]
+ fn over_max_size() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/build_failed/custom_signature_over_max_size.rs");
+ }
}
crates/evm-coder/tests/build_failed/custom_signature_over_max_size.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/evm-coder/tests/build_failed/custom_signature_over_max_size.rs
@@ -0,0 +1,33 @@
+#![allow(dead_code)]
+use std::str::from_utf8;
+
+use evm_coder::{
+ make_signature,
+ custom_signature::{SignatureUnit, SIGNATURE_SIZE_LIMIT},
+};
+
+trait Name {
+ const SIGNATURE: SignatureUnit;
+
+ fn name() -> &'static str {
+ from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8")
+ }
+}
+
+impl<T: Name> Name for Vec<T> {
+ evm_coder::make_signature!(new nameof(T) fixed("[]"));
+}
+
+struct MaxSize();
+impl Name for MaxSize {
+ const SIGNATURE: SignatureUnit = SignatureUnit {
+ data: [b'!'; SIGNATURE_SIZE_LIMIT],
+ len: SIGNATURE_SIZE_LIMIT,
+ };
+}
+
+const NAME: SignatureUnit = <Vec<MaxSize>>::SIGNATURE;
+
+fn main() {
+ assert!(false);
+}
crates/evm-coder/tests/build_failed/custom_signature_over_max_size.stderrdiffbeforeafterboth--- /dev/null
+++ b/crates/evm-coder/tests/build_failed/custom_signature_over_max_size.stderr
@@ -0,0 +1,19 @@
+error: any use of this value will cause an error
+ --> tests/build_failed/custom_signature_over_max_size.rs:18:2
+ |
+18 | evm_coder::make_signature!(new nameof(T) fixed("[]"));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 256 but the index is 256
+ |
+ = note: `#[deny(const_err)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+ = note: this error originates in the macro `make_signature` which comes from the expansion of the macro `evm_coder::make_signature` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: any use of this value will cause an error
+ --> tests/build_failed/custom_signature_over_max_size.rs:29:29
+ |
+29 | const NAME: SignatureUnit = <Vec<MaxSize>>::SIGNATURE;
+ | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
pallets/common/src/erc.rsdiffbeforeafterboth--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -35,10 +35,7 @@
use crate::{
Pallet, CollectionHandle, Config, CollectionProperties, SelfWeightOf,
- eth::{
- convert_cross_account_to_uint256, convert_cross_account_to_tuple,
- convert_tuple_to_cross_account,
- },
+ eth::{convert_cross_account_to_uint256, convert_tuple_to_cross_account},
weights::WeightInfo,
};
pallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -17,7 +17,6 @@
//! Implementation of magic contract
extern crate alloc;
-use alloc::string::ToString;
use core::marker::PhantomData;
use evm_coder::{
abi::AbiWriter,
pallets/fungible/src/erc.rsdiffbeforeafterboth--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -28,7 +28,6 @@
custom_signature::{SignatureUnit, FunctionSignature, SignaturePreferences},
make_signature,
};
-use pallet_common::eth::convert_tuple_to_cross_account;
use up_data_structs::CollectionMode;
use pallet_common::erc::{CommonEvmHandler, PrecompileResult};
use sp_std::vec::Vec;
pallets/refungible/src/erc.rsdiffbeforeafterboth--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -21,7 +21,6 @@
extern crate alloc;
-use alloc::string::ToString;
use core::{
char::{REPLACEMENT_CHARACTER, decode_utf16},
convert::TryInto,
@@ -39,7 +38,6 @@
use pallet_common::{
CollectionHandle, CollectionPropertyPermissions,
erc::{CommonEvmHandler, CollectionCall, static_property::key},
- eth::convert_tuple_to_cross_account,
};
use pallet_evm::{account::CrossAccountId, PrecompileHandle};
use pallet_evm_coder_substrate::{call, dispatch_to_evm};
pallets/unique/src/eth/mod.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Implementation of CollectionHelpers contract.1819use core::marker::PhantomData;20use ethereum as _;21use evm_coder::{22 execution::*,23 generate_stubgen, solidity, solidity_interface,24 types::*,25 custom_signature::{SignatureUnit, FunctionSignature, SignaturePreferences},26 make_signature, weight,27};28use frame_support::traits::Get;29use crate::Pallet;3031use pallet_common::{32 CollectionById,33 dispatch::CollectionDispatch,34 erc::{static_property::key, CollectionHelpersEvents},35 Pallet as PalletCommon,36};37use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};38use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder};39use sp_std::vec;40use up_data_structs::{41 CollectionDescription, CollectionMode, CollectionName, CollectionTokenPrefix,42 CreateCollectionData,43};4445use crate::{46 weights::WeightInfo, Config, SelfWeightOf, NftTransferBasket, FungibleTransferBasket,47 ReFungibleTransferBasket, NftApproveBasket, FungibleApproveBasket, RefungibleApproveBasket,48};4950use alloc::format;51use sp_std::vec::Vec;5253/// See [`CollectionHelpersCall`]54pub struct EvmCollectionHelpers<T: Config>(SubstrateRecorder<T>);55impl<T: Config> WithRecorder<T> for EvmCollectionHelpers<T> {56 fn recorder(&self) -> &SubstrateRecorder<T> {57 &self.058 }5960 fn into_recorder(self) -> SubstrateRecorder<T> {61 self.062 }63}6465fn convert_data<T: Config>(66 caller: caller,67 name: string,68 description: string,69 token_prefix: string,70) -> Result<(71 T::CrossAccountId,72 CollectionName,73 CollectionDescription,74 CollectionTokenPrefix,75)> {76 let caller = T::CrossAccountId::from_eth(caller);77 let name = name78 .encode_utf16()79 .collect::<Vec<u16>>()80 .try_into()81 .map_err(|_| error_field_too_long(stringify!(name), CollectionName::bound()))?;82 let description = description83 .encode_utf16()84 .collect::<Vec<u16>>()85 .try_into()86 .map_err(|_| {87 error_field_too_long(stringify!(description), CollectionDescription::bound())88 })?;89 let token_prefix = token_prefix.into_bytes().try_into().map_err(|_| {90 error_field_too_long(stringify!(token_prefix), CollectionTokenPrefix::bound())91 })?;92 Ok((caller, name, description, token_prefix))93}9495#[inline(always)]96fn create_collection_internal<T: Config>(97 caller: caller,98 value: value,99 name: string,100 collection_mode: CollectionMode,101 description: string,102 token_prefix: string,103) -> Result<address> {104 let (caller, name, description, token_prefix) =105 convert_data::<T>(caller, name, description, token_prefix)?;106 let data = CreateCollectionData {107 name,108 mode: collection_mode,109 description,110 token_prefix,111 ..Default::default()112 };113 check_sent_amount_equals_collection_creation_price::<T>(value)?;114 let collection_helpers_address =115 T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());116117 let collection_id = T::CollectionDispatch::create(118 caller.clone(),119 collection_helpers_address,120 data,121 Default::default(),122 )123 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;124 let address = pallet_common::eth::collection_id_to_address(collection_id);125 Ok(address)126}127128fn check_sent_amount_equals_collection_creation_price<T: Config>(value: value) -> Result<()> {129 let value = value.as_u128();130 let creation_price: u128 = T::CollectionCreationPrice::get()131 .try_into()132 .map_err(|_| ()) // workaround for `expect` requiring `Debug` trait133 .expect("Collection creation price should be convertible to u128");134 if value != creation_price {135 return Err(format!(136 "Sent amount not equals to collection creation price ({0})",137 creation_price138 )139 .into());140 }141 Ok(())142}143144/// @title Contract, which allows users to operate with collections145#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents))]146impl<T> EvmCollectionHelpers<T>147where148 T: Config + pallet_common::Config + pallet_nonfungible::Config + pallet_refungible::Config,149{150 /// Create an NFT collection151 /// @param name Name of the collection152 /// @param description Informative description of the collection153 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications154 /// @return address Address of the newly created collection155 #[weight(<SelfWeightOf<T>>::create_collection())]156 #[solidity(rename_selector = "createNFTCollection")]157 fn create_nft_collection(158 &mut self,159 caller: caller,160 value: value,161 name: string,162 description: string,163 token_prefix: string,164 ) -> Result<address> {165 let (caller, name, description, token_prefix) =166 convert_data::<T>(caller, name, description, token_prefix)?;167 let data = CreateCollectionData {168 name,169 mode: CollectionMode::NFT,170 description,171 token_prefix,172 ..Default::default()173 };174 check_sent_amount_equals_collection_creation_price::<T>(value)?;175 let collection_helpers_address =176 T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());177 let collection_id = T::CollectionDispatch::create(178 caller,179 collection_helpers_address,180 data,181 Default::default(),182 )183 .map_err(dispatch_to_evm::<T>)?;184185 let address = pallet_common::eth::collection_id_to_address(collection_id);186 Ok(address)187 }188 /// Create an NFT collection189 /// @param name Name of the collection190 /// @param description Informative description of the collection191 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications192 /// @return address Address of the newly created collection193 #[weight(<SelfWeightOf<T>>::create_collection())]194 #[deprecated(note = "mathod was renamed to `create_nft_collection`, prefer it instead")]195 #[solidity(hide)]196 fn create_nonfungible_collection(197 &mut self,198 caller: caller,199 value: value,200 name: string,201 description: string,202 token_prefix: string,203 ) -> Result<address> {204 create_collection_internal::<T>(205 caller,206 value,207 name,208 CollectionMode::NFT,209 description,210 token_prefix,211 )212 }213214 #[weight(<SelfWeightOf<T>>::create_collection())]215 #[solidity(rename_selector = "createRFTCollection")]216 fn create_rft_collection(217 &mut self,218 caller: caller,219 value: value,220 name: string,221 description: string,222 token_prefix: string,223 ) -> Result<address> {224 create_collection_internal::<T>(225 caller,226 value,227 name,228 CollectionMode::ReFungible,229 description,230 token_prefix,231 )232 }233234 #[weight(<SelfWeightOf<T>>::create_collection())]235 #[solidity(rename_selector = "createFTCollection")]236 fn create_fungible_collection(237 &mut self,238 caller: caller,239 value: value,240 name: string,241 decimals: uint8,242 description: string,243 token_prefix: string,244 ) -> Result<address> {245 create_collection_internal::<T>(246 caller,247 value,248 name,249 CollectionMode::Fungible(decimals),250 description,251 token_prefix,252 )253 }254255 #[solidity(rename_selector = "makeCollectionERC721MetadataCompatible")]256 fn make_collection_metadata_compatible(257 &mut self,258 caller: caller,259 collection: address,260 base_uri: string,261 ) -> Result<()> {262 let caller = T::CrossAccountId::from_eth(caller);263 let collection =264 pallet_common::eth::map_eth_to_id(&collection).ok_or("not a collection address")?;265 let mut collection =266 <crate::CollectionHandle<T>>::new(collection).ok_or("collection not found")?;267268 if !matches!(269 collection.mode,270 CollectionMode::NFT | CollectionMode::ReFungible271 ) {272 return Err("target collection should be either NFT or Refungible".into());273 }274275 self.recorder().consume_sstore()?;276 collection277 .check_is_owner_or_admin(&caller)278 .map_err(dispatch_to_evm::<T>)?;279280 if collection.flags.erc721metadata {281 return Err("target collection is already Erc721Metadata compatible".into());282 }283 collection.flags.erc721metadata = true;284285 let all_permissions = <pallet_common::CollectionPropertyPermissions<T>>::get(collection.id);286 if all_permissions.get(&key::url()).is_none() {287 self.recorder().consume_sstore()?;288 <PalletCommon<T>>::set_property_permission(289 &collection,290 &caller,291 up_data_structs::PropertyKeyPermission {292 key: key::url(),293 permission: up_data_structs::PropertyPermission {294 mutable: true,295 collection_admin: true,296 token_owner: false,297 },298 },299 )300 .map_err(dispatch_to_evm::<T>)?;301 }302 if all_permissions.get(&key::suffix()).is_none() {303 self.recorder().consume_sstore()?;304 <PalletCommon<T>>::set_property_permission(305 &collection,306 &caller,307 up_data_structs::PropertyKeyPermission {308 key: key::suffix(),309 permission: up_data_structs::PropertyPermission {310 mutable: true,311 collection_admin: true,312 token_owner: false,313 },314 },315 )316 .map_err(dispatch_to_evm::<T>)?;317 }318319 let all_properties = <pallet_common::CollectionProperties<T>>::get(collection.id);320 if all_properties.get(&key::base_uri()).is_none() && !base_uri.is_empty() {321 self.recorder().consume_sstore()?;322 <PalletCommon<T>>::set_collection_properties(323 &collection,324 &caller,325 vec![up_data_structs::Property {326 key: key::base_uri(),327 value: base_uri328 .into_bytes()329 .try_into()330 .map_err(|_| "base uri is too large")?,331 }],332 )333 .map_err(dispatch_to_evm::<T>)?;334 }335336 self.recorder().consume_sstore()?;337 collection.save().map_err(dispatch_to_evm::<T>)?;338339 Ok(())340 }341342 #[weight(<SelfWeightOf<T>>::destroy_collection())]343 fn destroy_collection(&mut self, caller: caller, collection_address: address) -> Result<void> {344 let caller = T::CrossAccountId::from_eth(caller);345346 let collection_id = pallet_common::eth::map_eth_to_id(&collection_address)347 .ok_or("Invalid collection address format")?;348 <Pallet<T>>::destroy_collection_internal(caller, collection_id)349 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)350 }351352 /// Check if a collection exists353 /// @param collectionAddress Address of the collection in question354 /// @return bool Does the collection exist?355 fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {356 if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {357 let collection_id = id;358 return Ok(<CollectionById<T>>::contains_key(collection_id));359 }360361 Ok(false)362 }363364 fn collection_creation_fee(&self) -> Result<value> {365 let price: u128 = T::CollectionCreationPrice::get()366 .try_into()367 .map_err(|_| ()) // workaround for `expect` requiring `Debug` trait368 .expect("Collection creation price should be convertible to u128");369 Ok(price.into())370 }371}372373/// Implements [`OnMethodCall`], which delegates call to [`EvmCollectionHelpers`]374pub struct CollectionHelpersOnMethodCall<T: Config>(PhantomData<*const T>);375impl<T: Config + pallet_nonfungible::Config + pallet_refungible::Config> OnMethodCall<T>376 for CollectionHelpersOnMethodCall<T>377{378 fn is_reserved(contract: &sp_core::H160) -> bool {379 contract == &T::ContractAddress::get()380 }381382 fn is_used(contract: &sp_core::H160) -> bool {383 contract == &T::ContractAddress::get()384 }385386 fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {387 if handle.code_address() != T::ContractAddress::get() {388 return None;389 }390391 let helpers =392 EvmCollectionHelpers::<T>(SubstrateRecorder::<T>::new(handle.remaining_gas()));393 pallet_evm_coder_substrate::call(handle, helpers)394 }395396 fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {397 (contract == &T::ContractAddress::get())398 .then(|| include_bytes!("./stubs/CollectionHelpers.raw").to_vec())399 }400}401402generate_stubgen!(collection_helper_impl, CollectionHelpersCall<()>, true);403generate_stubgen!(collection_helper_iface, CollectionHelpersCall<()>, false);404405fn error_field_too_long(feild: &str, bound: usize) -> Error {406 Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))407}1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Implementation of CollectionHelpers contract.1819use core::marker::PhantomData;20use ethereum as _;21use evm_coder::{22 execution::*,23 generate_stubgen, solidity, solidity_interface,24 types::*,25 custom_signature::{SignatureUnit, FunctionSignature, SignaturePreferences},26 make_signature, weight,27};28use frame_support::traits::Get;29use crate::Pallet;3031use pallet_common::{32 CollectionById,33 dispatch::CollectionDispatch,34 erc::{static_property::key, CollectionHelpersEvents},35 Pallet as PalletCommon,36};37use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};38use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder};39use sp_std::vec;40use up_data_structs::{41 CollectionDescription, CollectionMode, CollectionName, CollectionTokenPrefix,42 CreateCollectionData,43};4445use crate::{weights::WeightInfo, Config, SelfWeightOf};4647use alloc::format;48use sp_std::vec::Vec;4950/// See [`CollectionHelpersCall`]51pub struct EvmCollectionHelpers<T: Config>(SubstrateRecorder<T>);52impl<T: Config> WithRecorder<T> for EvmCollectionHelpers<T> {53 fn recorder(&self) -> &SubstrateRecorder<T> {54 &self.055 }5657 fn into_recorder(self) -> SubstrateRecorder<T> {58 self.059 }60}6162fn convert_data<T: Config>(63 caller: caller,64 name: string,65 description: string,66 token_prefix: string,67) -> Result<(68 T::CrossAccountId,69 CollectionName,70 CollectionDescription,71 CollectionTokenPrefix,72)> {73 let caller = T::CrossAccountId::from_eth(caller);74 let name = name75 .encode_utf16()76 .collect::<Vec<u16>>()77 .try_into()78 .map_err(|_| error_field_too_long(stringify!(name), CollectionName::bound()))?;79 let description = description80 .encode_utf16()81 .collect::<Vec<u16>>()82 .try_into()83 .map_err(|_| {84 error_field_too_long(stringify!(description), CollectionDescription::bound())85 })?;86 let token_prefix = token_prefix.into_bytes().try_into().map_err(|_| {87 error_field_too_long(stringify!(token_prefix), CollectionTokenPrefix::bound())88 })?;89 Ok((caller, name, description, token_prefix))90}9192#[inline(always)]93fn create_collection_internal<T: Config>(94 caller: caller,95 value: value,96 name: string,97 collection_mode: CollectionMode,98 description: string,99 token_prefix: string,100) -> Result<address> {101 let (caller, name, description, token_prefix) =102 convert_data::<T>(caller, name, description, token_prefix)?;103 let data = CreateCollectionData {104 name,105 mode: collection_mode,106 description,107 token_prefix,108 ..Default::default()109 };110 check_sent_amount_equals_collection_creation_price::<T>(value)?;111 let collection_helpers_address =112 T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());113114 let collection_id = T::CollectionDispatch::create(115 caller.clone(),116 collection_helpers_address,117 data,118 Default::default(),119 )120 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;121 let address = pallet_common::eth::collection_id_to_address(collection_id);122 Ok(address)123}124125fn check_sent_amount_equals_collection_creation_price<T: Config>(value: value) -> Result<()> {126 let value = value.as_u128();127 let creation_price: u128 = T::CollectionCreationPrice::get()128 .try_into()129 .map_err(|_| ()) // workaround for `expect` requiring `Debug` trait130 .expect("Collection creation price should be convertible to u128");131 if value != creation_price {132 return Err(format!(133 "Sent amount not equals to collection creation price ({0})",134 creation_price135 )136 .into());137 }138 Ok(())139}140141/// @title Contract, which allows users to operate with collections142#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents))]143impl<T> EvmCollectionHelpers<T>144where145 T: Config + pallet_common::Config + pallet_nonfungible::Config + pallet_refungible::Config,146{147 /// Create an NFT collection148 /// @param name Name of the collection149 /// @param description Informative description of the collection150 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications151 /// @return address Address of the newly created collection152 #[weight(<SelfWeightOf<T>>::create_collection())]153 #[solidity(rename_selector = "createNFTCollection")]154 fn create_nft_collection(155 &mut self,156 caller: caller,157 value: value,158 name: string,159 description: string,160 token_prefix: string,161 ) -> Result<address> {162 let (caller, name, description, token_prefix) =163 convert_data::<T>(caller, name, description, token_prefix)?;164 let data = CreateCollectionData {165 name,166 mode: CollectionMode::NFT,167 description,168 token_prefix,169 ..Default::default()170 };171 check_sent_amount_equals_collection_creation_price::<T>(value)?;172 let collection_helpers_address =173 T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());174 let collection_id = T::CollectionDispatch::create(175 caller,176 collection_helpers_address,177 data,178 Default::default(),179 )180 .map_err(dispatch_to_evm::<T>)?;181182 let address = pallet_common::eth::collection_id_to_address(collection_id);183 Ok(address)184 }185 /// Create an NFT collection186 /// @param name Name of the collection187 /// @param description Informative description of the collection188 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications189 /// @return address Address of the newly created collection190 #[weight(<SelfWeightOf<T>>::create_collection())]191 #[deprecated(note = "mathod was renamed to `create_nft_collection`, prefer it instead")]192 #[solidity(hide)]193 fn create_nonfungible_collection(194 &mut self,195 caller: caller,196 value: value,197 name: string,198 description: string,199 token_prefix: string,200 ) -> Result<address> {201 create_collection_internal::<T>(202 caller,203 value,204 name,205 CollectionMode::NFT,206 description,207 token_prefix,208 )209 }210211 #[weight(<SelfWeightOf<T>>::create_collection())]212 #[solidity(rename_selector = "createRFTCollection")]213 fn create_rft_collection(214 &mut self,215 caller: caller,216 value: value,217 name: string,218 description: string,219 token_prefix: string,220 ) -> Result<address> {221 create_collection_internal::<T>(222 caller,223 value,224 name,225 CollectionMode::ReFungible,226 description,227 token_prefix,228 )229 }230231 #[weight(<SelfWeightOf<T>>::create_collection())]232 #[solidity(rename_selector = "createFTCollection")]233 fn create_fungible_collection(234 &mut self,235 caller: caller,236 value: value,237 name: string,238 decimals: uint8,239 description: string,240 token_prefix: string,241 ) -> Result<address> {242 create_collection_internal::<T>(243 caller,244 value,245 name,246 CollectionMode::Fungible(decimals),247 description,248 token_prefix,249 )250 }251252 #[solidity(rename_selector = "makeCollectionERC721MetadataCompatible")]253 fn make_collection_metadata_compatible(254 &mut self,255 caller: caller,256 collection: address,257 base_uri: string,258 ) -> Result<()> {259 let caller = T::CrossAccountId::from_eth(caller);260 let collection =261 pallet_common::eth::map_eth_to_id(&collection).ok_or("not a collection address")?;262 let mut collection =263 <crate::CollectionHandle<T>>::new(collection).ok_or("collection not found")?;264265 if !matches!(266 collection.mode,267 CollectionMode::NFT | CollectionMode::ReFungible268 ) {269 return Err("target collection should be either NFT or Refungible".into());270 }271272 self.recorder().consume_sstore()?;273 collection274 .check_is_owner_or_admin(&caller)275 .map_err(dispatch_to_evm::<T>)?;276277 if collection.flags.erc721metadata {278 return Err("target collection is already Erc721Metadata compatible".into());279 }280 collection.flags.erc721metadata = true;281282 let all_permissions = <pallet_common::CollectionPropertyPermissions<T>>::get(collection.id);283 if all_permissions.get(&key::url()).is_none() {284 self.recorder().consume_sstore()?;285 <PalletCommon<T>>::set_property_permission(286 &collection,287 &caller,288 up_data_structs::PropertyKeyPermission {289 key: key::url(),290 permission: up_data_structs::PropertyPermission {291 mutable: true,292 collection_admin: true,293 token_owner: false,294 },295 },296 )297 .map_err(dispatch_to_evm::<T>)?;298 }299 if all_permissions.get(&key::suffix()).is_none() {300 self.recorder().consume_sstore()?;301 <PalletCommon<T>>::set_property_permission(302 &collection,303 &caller,304 up_data_structs::PropertyKeyPermission {305 key: key::suffix(),306 permission: up_data_structs::PropertyPermission {307 mutable: true,308 collection_admin: true,309 token_owner: false,310 },311 },312 )313 .map_err(dispatch_to_evm::<T>)?;314 }315316 let all_properties = <pallet_common::CollectionProperties<T>>::get(collection.id);317 if all_properties.get(&key::base_uri()).is_none() && !base_uri.is_empty() {318 self.recorder().consume_sstore()?;319 <PalletCommon<T>>::set_collection_properties(320 &collection,321 &caller,322 vec![up_data_structs::Property {323 key: key::base_uri(),324 value: base_uri325 .into_bytes()326 .try_into()327 .map_err(|_| "base uri is too large")?,328 }],329 )330 .map_err(dispatch_to_evm::<T>)?;331 }332333 self.recorder().consume_sstore()?;334 collection.save().map_err(dispatch_to_evm::<T>)?;335336 Ok(())337 }338339 #[weight(<SelfWeightOf<T>>::destroy_collection())]340 fn destroy_collection(&mut self, caller: caller, collection_address: address) -> Result<void> {341 let caller = T::CrossAccountId::from_eth(caller);342343 let collection_id = pallet_common::eth::map_eth_to_id(&collection_address)344 .ok_or("Invalid collection address format")?;345 <Pallet<T>>::destroy_collection_internal(caller, collection_id)346 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)347 }348349 /// Check if a collection exists350 /// @param collectionAddress Address of the collection in question351 /// @return bool Does the collection exist?352 fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {353 if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {354 let collection_id = id;355 return Ok(<CollectionById<T>>::contains_key(collection_id));356 }357358 Ok(false)359 }360361 fn collection_creation_fee(&self) -> Result<value> {362 let price: u128 = T::CollectionCreationPrice::get()363 .try_into()364 .map_err(|_| ()) // workaround for `expect` requiring `Debug` trait365 .expect("Collection creation price should be convertible to u128");366 Ok(price.into())367 }368}369370/// Implements [`OnMethodCall`], which delegates call to [`EvmCollectionHelpers`]371pub struct CollectionHelpersOnMethodCall<T: Config>(PhantomData<*const T>);372impl<T: Config + pallet_nonfungible::Config + pallet_refungible::Config> OnMethodCall<T>373 for CollectionHelpersOnMethodCall<T>374{375 fn is_reserved(contract: &sp_core::H160) -> bool {376 contract == &T::ContractAddress::get()377 }378379 fn is_used(contract: &sp_core::H160) -> bool {380 contract == &T::ContractAddress::get()381 }382383 fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {384 if handle.code_address() != T::ContractAddress::get() {385 return None;386 }387388 let helpers =389 EvmCollectionHelpers::<T>(SubstrateRecorder::<T>::new(handle.remaining_gas()));390 pallet_evm_coder_substrate::call(handle, helpers)391 }392393 fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {394 (contract == &T::ContractAddress::get())395 .then(|| include_bytes!("./stubs/CollectionHelpers.raw").to_vec())396 }397}398399generate_stubgen!(collection_helper_impl, CollectionHelpersCall<()>, true);400generate_stubgen!(collection_helper_iface, CollectionHelpersCall<()>, false);401402fn error_field_too_long(feild: &str, bound: usize) -> Error {403 Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))404}runtime/common/config/pallets/scheduler.rsdiffbeforeafterboth--- a/runtime/common/config/pallets/scheduler.rs
+++ b/runtime/common/config/pallets/scheduler.rs
@@ -25,7 +25,7 @@
use codec::Decode;
use crate::{
runtime_common::{scheduler::SchedulerPaymentExecutor, config::substrate::RuntimeBlockWeights},
- Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, OriginCaller, Balances,
+ Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, OriginCaller,
};
use pallet_unique_scheduler_v2::ScheduledEnsureOriginSuccess;
use up_common::types::AccountId;
runtime/common/scheduler.rsdiffbeforeafterboth--- a/runtime/common/scheduler.rs
+++ b/runtime/common/scheduler.rs
@@ -14,19 +14,16 @@
// You should have received a copy of the GNU General Public License
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-use frame_support::{
- traits::NamedReservableCurrency,
- dispatch::{GetDispatchInfo, PostDispatchInfo, DispatchInfo},
-};
+use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo, DispatchInfo};
use sp_runtime::{
traits::{Dispatchable, Applyable, Member},
generic::Era,
transaction_validity::TransactionValidityError,
- DispatchErrorWithPostInfo, DispatchError,
+ DispatchErrorWithPostInfo,
};
use codec::Encode;
-use crate::{Runtime, RuntimeCall, RuntimeOrigin, Balances};
-use up_common::types::{AccountId, Balance};
+use crate::{Runtime, RuntimeCall, RuntimeOrigin};
+use up_common::types::AccountId;
use fp_self_contained::SelfContainedCall;
use pallet_unique_scheduler_v2::DispatchCall;
use pallet_transaction_payment::ChargeTransactionPayment;