difftreelog
chore fix cargo fmt
in: master
4 files changed
node/cli/src/command.rsdiffbeforeafterboth--- a/node/cli/src/command.rs
+++ b/node/cli/src/command.rs
@@ -33,9 +33,7 @@
// limitations under the License.
use crate::{
- chain_spec::{
- self, RuntimeId, RuntimeIdentification, ServiceId, ServiceIdentification, default_runtime,
- },
+ chain_spec::{self, RuntimeId, RuntimeIdentification, ServiceId, ServiceIdentification},
cli::{Cli, RelayChainCli, Subcommand},
service::{new_partial, start_node, start_dev_node},
};
@@ -46,7 +44,7 @@
#[cfg(feature = "quartz-runtime")]
use crate::service::QuartzRuntimeExecutor;
-use crate::service::{OpalRuntimeExecutor, DefaultRuntimeExecutor};
+use crate::service::OpalRuntimeExecutor;
use codec::Encode;
use cumulus_primitives_core::ParaId;
node/cli/src/service.rsdiffbeforeafterboth--- a/node/cli/src/service.rs
+++ b/node/cli/src/service.rs
@@ -46,7 +46,6 @@
use cumulus_relay_chain_rpc_interface::{RelayChainRpcInterface, create_client_and_start_worker};
// Substrate Imports
-use sc_client_api::ExecutorProvider;
use sc_executor::NativeElseWasmExecutor;
use sc_executor::NativeExecutionDispatch;
use sc_network::{NetworkService, NetworkBlock};
@@ -83,15 +82,6 @@
/// Opal native executor instance.
pub struct OpalRuntimeExecutor;
-
-#[cfg(feature = "unique-runtime")]
-pub type DefaultRuntimeExecutor = UniqueRuntimeExecutor;
-
-#[cfg(all(not(feature = "unique-runtime"), feature = "quartz-runtime"))]
-pub type DefaultRuntimeExecutor = QuartzRuntimeExecutor;
-
-#[cfg(all(not(feature = "unique-runtime"), not(feature = "quartz-runtime")))]
-pub type DefaultRuntimeExecutor = OpalRuntimeExecutor;
#[cfg(feature = "unique-runtime")]
impl NativeExecutionDispatch for UniqueRuntimeExecutor {
pallets/common/src/erc.rsdiffbeforeafterboth--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -27,7 +27,7 @@
use sp_std::vec::Vec;
use up_data_structs::{
AccessMode, CollectionMode, CollectionPermissions, OwnerRestrictedSet, Property,
- SponsoringRateLimit, SponsorshipState, PropertyKey,
+ SponsoringRateLimit, SponsorshipState,
};
use alloc::format;
@@ -106,7 +106,6 @@
caller: caller,
properties: Vec<(string, bytes)>,
) -> Result<void> {
-
let caller = T::CrossAccountId::from_eth(caller);
let properties = properties
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::{execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};22use frame_support::traits::Get;2324use crate::Pallet;2526use pallet_common::{27 CollectionById,28 dispatch::CollectionDispatch,29 erc::{30 static_property::key,31 CollectionHelpersEvents,32 },33 Pallet as PalletCommon,34 35};36use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};37use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder};38use sp_std::vec;39use up_data_structs::{40 CollectionDescription, CollectionMode, CollectionName, CollectionTokenPrefix,41 CreateCollectionData, PropertyValue,42};4344use crate::{weights::WeightInfo, Config, SelfWeightOf};4546use alloc::format;47use sp_std::vec::Vec;4849/// See [`CollectionHelpersCall`]50pub struct EvmCollectionHelpers<T: Config>(SubstrateRecorder<T>);51impl<T: Config> WithRecorder<T> for EvmCollectionHelpers<T> {52 fn recorder(&self) -> &SubstrateRecorder<T> {53 &self.054 }5556 fn into_recorder(self) -> SubstrateRecorder<T> {57 self.058 }59}6061fn convert_data<T: Config>(62 caller: caller,63 name: string,64 description: string,65 token_prefix: string,66) -> Result<(67 T::CrossAccountId,68 CollectionName,69 CollectionDescription,70 CollectionTokenPrefix,71)> {72 let caller = T::CrossAccountId::from_eth(caller);73 let name = name74 .encode_utf16()75 .collect::<Vec<u16>>()76 .try_into()77 .map_err(|_| error_field_too_long(stringify!(name), CollectionName::bound()))?;78 let description = description79 .encode_utf16()80 .collect::<Vec<u16>>()81 .try_into()82 .map_err(|_| {83 error_field_too_long(stringify!(description), CollectionDescription::bound())84 })?;85 let token_prefix = token_prefix.into_bytes().try_into().map_err(|_| {86 error_field_too_long(stringify!(token_prefix), CollectionTokenPrefix::bound())87 })?;88 Ok((caller, name, description, token_prefix))89}9091fn create_refungible_collection_internal<T: Config>(92 caller: caller,93 value: value,94 name: string,95 description: string,96 token_prefix: string,97) -> Result<address> {98 self::create_collection_internal::<T>(99 caller,100 value,101 name,102 CollectionMode::ReFungible,103 description,104 token_prefix105 )106}107108#[inline(always)]109fn create_collection_internal<T: Config>(110 caller: caller,111 value: value,112 name: string,113 collection_mode: CollectionMode,114 description: string,115 token_prefix: string,116) -> Result<address> {117 let (caller, name, description, token_prefix) =118 convert_data::<T>(caller, name, description, token_prefix)?;119 let data = CreateCollectionData {120 name,121 mode: collection_mode,122 description,123 token_prefix,124 ..Default::default()125 };126 check_sent_amount_equals_collection_creation_price::<T>(value)?;127 let collection_helpers_address =128 T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());129130 let collection_id = T::CollectionDispatch::create(131 caller.clone(),132 collection_helpers_address,133 data,134 Default::default(),135 )136 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;137 let address = pallet_common::eth::collection_id_to_address(collection_id);138 Ok(address)139}140141fn check_sent_amount_equals_collection_creation_price<T: Config>(value: value) -> Result<()> {142 let value = value.as_u128();143 let creation_price: u128 = T::CollectionCreationPrice::get()144 .try_into()145 .map_err(|_| ()) // workaround for `expect` requiring `Debug` trait146 .expect("Collection creation price should be convertible to u128");147 if value != creation_price {148 return Err(format!(149 "Sent amount not equals to collection creation price ({0})",150 creation_price151 )152 .into());153 }154 Ok(())155}156157/// @title Contract, which allows users to operate with collections158#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents))]159impl<T> EvmCollectionHelpers<T>160where161 T: Config + pallet_common::Config + pallet_nonfungible::Config + pallet_refungible::Config,162{163 /// Create an NFT collection164 /// @param name Name of the collection165 /// @param description Informative description of the collection166 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications167 /// @return address Address of the newly created collection168 #[weight(<SelfWeightOf<T>>::create_collection())]169 #[solidity(rename_selector = "createNFTCollection")]170 fn create_nft_collection(171 &mut self,172 caller: caller,173 value: value,174 name: string,175 description: string,176 token_prefix: string,177 ) -> Result<address> {178 let (caller, name, description, token_prefix) =179 convert_data::<T>(caller, name, description, token_prefix)?;180 let data = CreateCollectionData {181 name,182 mode: CollectionMode::NFT,183 description,184 token_prefix,185 ..Default::default()186 };187 check_sent_amount_equals_collection_creation_price::<T>(value)?;188 let collection_helpers_address =189 T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());190 let collection_id = T::CollectionDispatch::create(191 caller,192 collection_helpers_address,193 data,194 Default::default(),195 )196 .map_err(dispatch_to_evm::<T>)?;197198 let address = pallet_common::eth::collection_id_to_address(collection_id);199 Ok(address)200 }201 /// Create an NFT collection202 /// @param name Name of the collection203 /// @param description Informative description of the collection204 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications205 /// @return address Address of the newly created collection206 #[weight(<SelfWeightOf<T>>::create_collection())]207 #[deprecated(note = "mathod was renamed to `create_nft_collection`, prefer it instead")]208 #[solidity(hide)]209 fn create_nonfungible_collection(210 &mut self,211 caller: caller,212 value: value,213 name: string,214 description: string,215 token_prefix: string,216 ) -> Result<address> {217 create_collection_internal::<T>(218 caller,219 value,220 name,221 CollectionMode::NFT,222 description,223 token_prefix,224 )225 }226227 #[weight(<SelfWeightOf<T>>::create_collection())]228 #[solidity(rename_selector = "createRFTCollection")]229 fn create_rft_collection(230 &mut self,231 caller: caller,232 value: value,233 name: string,234 description: string,235 token_prefix: string,236 ) -> Result<address> {237 create_collection_internal::<T>(238 caller,239 value,240 name,241 CollectionMode::ReFungible,242 description,243 token_prefix,244 )245 }246247 #[weight(<SelfWeightOf<T>>::create_collection())]248 #[solidity(rename_selector = "createERC721MetadataCompatibleRFTCollection")]249 fn create_refungible_collection_with_properties(250 &mut self,251 caller: caller,252 value: value,253 name: string,254 description: string,255 token_prefix: string,256 base_uri: string,257 ) -> Result<address> {258 create_collection_internal::<T>(259 caller,260 value,261 name,262 CollectionMode::ReFungible,263 description,264 token_prefix,265 )266 }267268 #[weight(<SelfWeightOf<T>>::create_collection())]269 #[solidity(rename_selector = "createFTCollection")]270 fn create_fungible_collection(271 &mut self,272 caller: caller,273 value: value,274 name: string,275 decimals: uint8,276 description: string,277 token_prefix: string,278 ) -> Result<address> {279 create_collection_internal::<T>(280 caller,281 value,282 name,283 CollectionMode::Fungible(decimals),284 description,285 token_prefix,286 )287 }288289 #[solidity(rename_selector = "makeCollectionERC721MetadataCompatible")]290 fn make_collection_metadata_compatible(291 &mut self,292 caller: caller,293 collection: address,294 base_uri: string,295 ) -> Result<()> {296 let caller = T::CrossAccountId::from_eth(caller);297 let collection =298 pallet_common::eth::map_eth_to_id(&collection).ok_or("not a collection address")?;299 let mut collection =300 <crate::CollectionHandle<T>>::new(collection).ok_or("collection not found")?;301302 if !matches!(303 collection.mode,304 CollectionMode::NFT | CollectionMode::ReFungible305 ) {306 return Err("target collection should be either NFT or Refungible".into());307 }308309 self.recorder().consume_sstore()?;310 collection311 .check_is_owner_or_admin(&caller)312 .map_err(dispatch_to_evm::<T>)?;313314 if collection.flags.erc721metadata {315 return Err("target collection is already Erc721Metadata compatible".into());316 }317 collection.flags.erc721metadata = true;318319 let all_permissions = <pallet_common::CollectionPropertyPermissions<T>>::get(collection.id);320 if all_permissions.get(&key::url()).is_none() {321 self.recorder().consume_sstore()?;322 <PalletCommon<T>>::set_property_permission(323 &collection,324 &caller,325 up_data_structs::PropertyKeyPermission {326 key: key::url(),327 permission: up_data_structs::PropertyPermission {328 mutable: true,329 collection_admin: true,330 token_owner: false,331 },332 },333 )334 .map_err(dispatch_to_evm::<T>)?;335 }336 if all_permissions.get(&key::suffix()).is_none() {337 self.recorder().consume_sstore()?;338 <PalletCommon<T>>::set_property_permission(339 &collection,340 &caller,341 up_data_structs::PropertyKeyPermission {342 key: key::suffix(),343 permission: up_data_structs::PropertyPermission {344 mutable: true,345 collection_admin: true,346 token_owner: false,347 },348 },349 )350 .map_err(dispatch_to_evm::<T>)?;351 }352353 let all_properties = <pallet_common::CollectionProperties<T>>::get(collection.id);354 if all_properties.get(&key::base_uri()).is_none() && !base_uri.is_empty() {355 self.recorder().consume_sstore()?;356 <PalletCommon<T>>::set_collection_properties(357 &collection,358 &caller,359 vec![up_data_structs::Property {360 key: key::base_uri(),361 value: base_uri362 .into_bytes()363 .try_into()364 .map_err(|_| "base uri is too large")?,365 }],366 )367 .map_err(dispatch_to_evm::<T>)?;368 }369370 self.recorder().consume_sstore()?;371 collection.save().map_err(dispatch_to_evm::<T>)?;372373 Ok(())374 }375376 #[weight(<SelfWeightOf<T>>::destroy_collection())]377 fn destroy_collection(&mut self, caller: caller, collection_address: address) -> Result<void> {378 let caller = T::CrossAccountId::from_eth(caller);379380 let collection_id = pallet_common::eth::map_eth_to_id(&collection_address)381 .ok_or("Invalid collection address format")?;382 <Pallet<T>>::destroy_collection_internal(caller, collection_id)383 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)384 }385386 /// Check if a collection exists387 /// @param collectionAddress Address of the collection in question388 /// @return bool Does the collection exist?389 fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {390 if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {391 let collection_id = id;392 return Ok(<CollectionById<T>>::contains_key(collection_id));393 }394395 Ok(false)396 }397398 fn collection_creation_fee(&self) -> Result<value> {399 let price: u128 = T::CollectionCreationPrice::get()400 .try_into()401 .map_err(|_| ()) // workaround for `expect` requiring `Debug` trait402 .expect("Collection creation price should be convertible to u128");403 Ok(price.into())404 }405}406407/// Implements [`OnMethodCall`], which delegates call to [`EvmCollectionHelpers`]408pub struct CollectionHelpersOnMethodCall<T: Config>(PhantomData<*const T>);409impl<T: Config + pallet_nonfungible::Config + pallet_refungible::Config> OnMethodCall<T>410 for CollectionHelpersOnMethodCall<T>411{412 fn is_reserved(contract: &sp_core::H160) -> bool {413 contract == &T::ContractAddress::get()414 }415416 fn is_used(contract: &sp_core::H160) -> bool {417 contract == &T::ContractAddress::get()418 }419420 fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {421 if handle.code_address() != T::ContractAddress::get() {422 return None;423 }424425 let helpers =426 EvmCollectionHelpers::<T>(SubstrateRecorder::<T>::new(handle.remaining_gas()));427 pallet_evm_coder_substrate::call(handle, helpers)428 }429430 fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {431 (contract == &T::ContractAddress::get())432 .then(|| include_bytes!("./stubs/CollectionHelpers.raw").to_vec())433 }434}435436generate_stubgen!(collection_helper_impl, CollectionHelpersCall<()>, true);437generate_stubgen!(collection_helper_iface, CollectionHelpersCall<()>, false);438439fn error_field_too_long(feild: &str, bound: usize) -> Error {440 Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))441}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::{execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};22use frame_support::traits::Get;2324use crate::Pallet;2526use pallet_common::{27 CollectionById,28 dispatch::CollectionDispatch,29 erc::{static_property::key, CollectionHelpersEvents},30 Pallet as PalletCommon,31};32use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};33use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder};34use sp_std::vec;35use up_data_structs::{36 CollectionDescription, CollectionMode, CollectionName, CollectionTokenPrefix,37 CreateCollectionData,38};3940use crate::{weights::WeightInfo, Config, SelfWeightOf};4142use alloc::format;43use sp_std::vec::Vec;4445/// See [`CollectionHelpersCall`]46pub struct EvmCollectionHelpers<T: Config>(SubstrateRecorder<T>);47impl<T: Config> WithRecorder<T> for EvmCollectionHelpers<T> {48 fn recorder(&self) -> &SubstrateRecorder<T> {49 &self.050 }5152 fn into_recorder(self) -> SubstrateRecorder<T> {53 self.054 }55}5657fn convert_data<T: Config>(58 caller: caller,59 name: string,60 description: string,61 token_prefix: string,62) -> Result<(63 T::CrossAccountId,64 CollectionName,65 CollectionDescription,66 CollectionTokenPrefix,67)> {68 let caller = T::CrossAccountId::from_eth(caller);69 let name = name70 .encode_utf16()71 .collect::<Vec<u16>>()72 .try_into()73 .map_err(|_| error_field_too_long(stringify!(name), CollectionName::bound()))?;74 let description = description75 .encode_utf16()76 .collect::<Vec<u16>>()77 .try_into()78 .map_err(|_| {79 error_field_too_long(stringify!(description), CollectionDescription::bound())80 })?;81 let token_prefix = token_prefix.into_bytes().try_into().map_err(|_| {82 error_field_too_long(stringify!(token_prefix), CollectionTokenPrefix::bound())83 })?;84 Ok((caller, name, description, token_prefix))85}8687#[inline(always)]88fn create_collection_internal<T: Config>(89 caller: caller,90 value: value,91 name: string,92 collection_mode: CollectionMode,93 description: string,94 token_prefix: string,95) -> Result<address> {96 let (caller, name, description, token_prefix) =97 convert_data::<T>(caller, name, description, token_prefix)?;98 let data = CreateCollectionData {99 name,100 mode: collection_mode,101 description,102 token_prefix,103 ..Default::default()104 };105 check_sent_amount_equals_collection_creation_price::<T>(value)?;106 let collection_helpers_address =107 T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());108109 let collection_id = T::CollectionDispatch::create(110 caller.clone(),111 collection_helpers_address,112 data,113 Default::default(),114 )115 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;116 let address = pallet_common::eth::collection_id_to_address(collection_id);117 Ok(address)118}119120fn check_sent_amount_equals_collection_creation_price<T: Config>(value: value) -> Result<()> {121 let value = value.as_u128();122 let creation_price: u128 = T::CollectionCreationPrice::get()123 .try_into()124 .map_err(|_| ()) // workaround for `expect` requiring `Debug` trait125 .expect("Collection creation price should be convertible to u128");126 if value != creation_price {127 return Err(format!(128 "Sent amount not equals to collection creation price ({0})",129 creation_price130 )131 .into());132 }133 Ok(())134}135136/// @title Contract, which allows users to operate with collections137#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents))]138impl<T> EvmCollectionHelpers<T>139where140 T: Config + pallet_common::Config + pallet_nonfungible::Config + pallet_refungible::Config,141{142 /// Create an NFT collection143 /// @param name Name of the collection144 /// @param description Informative description of the collection145 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications146 /// @return address Address of the newly created collection147 #[weight(<SelfWeightOf<T>>::create_collection())]148 #[solidity(rename_selector = "createNFTCollection")]149 fn create_nft_collection(150 &mut self,151 caller: caller,152 value: value,153 name: string,154 description: string,155 token_prefix: string,156 ) -> Result<address> {157 let (caller, name, description, token_prefix) =158 convert_data::<T>(caller, name, description, token_prefix)?;159 let data = CreateCollectionData {160 name,161 mode: CollectionMode::NFT,162 description,163 token_prefix,164 ..Default::default()165 };166 check_sent_amount_equals_collection_creation_price::<T>(value)?;167 let collection_helpers_address =168 T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());169 let collection_id = T::CollectionDispatch::create(170 caller,171 collection_helpers_address,172 data,173 Default::default(),174 )175 .map_err(dispatch_to_evm::<T>)?;176177 let address = pallet_common::eth::collection_id_to_address(collection_id);178 Ok(address)179 }180 /// Create an NFT collection181 /// @param name Name of the collection182 /// @param description Informative description of the collection183 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications184 /// @return address Address of the newly created collection185 #[weight(<SelfWeightOf<T>>::create_collection())]186 #[deprecated(note = "mathod was renamed to `create_nft_collection`, prefer it instead")]187 #[solidity(hide)]188 fn create_nonfungible_collection(189 &mut self,190 caller: caller,191 value: value,192 name: string,193 description: string,194 token_prefix: string,195 ) -> Result<address> {196 create_collection_internal::<T>(197 caller,198 value,199 name,200 CollectionMode::NFT,201 description,202 token_prefix,203 )204 }205206 #[weight(<SelfWeightOf<T>>::create_collection())]207 #[solidity(rename_selector = "createRFTCollection")]208 fn create_rft_collection(209 &mut self,210 caller: caller,211 value: value,212 name: string,213 description: string,214 token_prefix: string,215 ) -> Result<address> {216 create_collection_internal::<T>(217 caller,218 value,219 name,220 CollectionMode::ReFungible,221 description,222 token_prefix,223 )224 }225226 #[weight(<SelfWeightOf<T>>::create_collection())]227 #[solidity(rename_selector = "createFTCollection")]228 fn create_fungible_collection(229 &mut self,230 caller: caller,231 value: value,232 name: string,233 decimals: uint8,234 description: string,235 token_prefix: string,236 ) -> Result<address> {237 create_collection_internal::<T>(238 caller,239 value,240 name,241 CollectionMode::Fungible(decimals),242 description,243 token_prefix,244 )245 }246247 #[solidity(rename_selector = "makeCollectionERC721MetadataCompatible")]248 fn make_collection_metadata_compatible(249 &mut self,250 caller: caller,251 collection: address,252 base_uri: string,253 ) -> Result<()> {254 let caller = T::CrossAccountId::from_eth(caller);255 let collection =256 pallet_common::eth::map_eth_to_id(&collection).ok_or("not a collection address")?;257 let mut collection =258 <crate::CollectionHandle<T>>::new(collection).ok_or("collection not found")?;259260 if !matches!(261 collection.mode,262 CollectionMode::NFT | CollectionMode::ReFungible263 ) {264 return Err("target collection should be either NFT or Refungible".into());265 }266267 self.recorder().consume_sstore()?;268 collection269 .check_is_owner_or_admin(&caller)270 .map_err(dispatch_to_evm::<T>)?;271272 if collection.flags.erc721metadata {273 return Err("target collection is already Erc721Metadata compatible".into());274 }275 collection.flags.erc721metadata = true;276277 let all_permissions = <pallet_common::CollectionPropertyPermissions<T>>::get(collection.id);278 if all_permissions.get(&key::url()).is_none() {279 self.recorder().consume_sstore()?;280 <PalletCommon<T>>::set_property_permission(281 &collection,282 &caller,283 up_data_structs::PropertyKeyPermission {284 key: key::url(),285 permission: up_data_structs::PropertyPermission {286 mutable: true,287 collection_admin: true,288 token_owner: false,289 },290 },291 )292 .map_err(dispatch_to_evm::<T>)?;293 }294 if all_permissions.get(&key::suffix()).is_none() {295 self.recorder().consume_sstore()?;296 <PalletCommon<T>>::set_property_permission(297 &collection,298 &caller,299 up_data_structs::PropertyKeyPermission {300 key: key::suffix(),301 permission: up_data_structs::PropertyPermission {302 mutable: true,303 collection_admin: true,304 token_owner: false,305 },306 },307 )308 .map_err(dispatch_to_evm::<T>)?;309 }310311 let all_properties = <pallet_common::CollectionProperties<T>>::get(collection.id);312 if all_properties.get(&key::base_uri()).is_none() && !base_uri.is_empty() {313 self.recorder().consume_sstore()?;314 <PalletCommon<T>>::set_collection_properties(315 &collection,316 &caller,317 vec![up_data_structs::Property {318 key: key::base_uri(),319 value: base_uri320 .into_bytes()321 .try_into()322 .map_err(|_| "base uri is too large")?,323 }],324 )325 .map_err(dispatch_to_evm::<T>)?;326 }327328 self.recorder().consume_sstore()?;329 collection.save().map_err(dispatch_to_evm::<T>)?;330331 Ok(())332 }333334 #[weight(<SelfWeightOf<T>>::destroy_collection())]335 fn destroy_collection(&mut self, caller: caller, collection_address: address) -> Result<void> {336 let caller = T::CrossAccountId::from_eth(caller);337338 let collection_id = pallet_common::eth::map_eth_to_id(&collection_address)339 .ok_or("Invalid collection address format")?;340 <Pallet<T>>::destroy_collection_internal(caller, collection_id)341 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)342 }343344 /// Check if a collection exists345 /// @param collectionAddress Address of the collection in question346 /// @return bool Does the collection exist?347 fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {348 if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {349 let collection_id = id;350 return Ok(<CollectionById<T>>::contains_key(collection_id));351 }352353 Ok(false)354 }355356 fn collection_creation_fee(&self) -> Result<value> {357 let price: u128 = T::CollectionCreationPrice::get()358 .try_into()359 .map_err(|_| ()) // workaround for `expect` requiring `Debug` trait360 .expect("Collection creation price should be convertible to u128");361 Ok(price.into())362 }363}364365/// Implements [`OnMethodCall`], which delegates call to [`EvmCollectionHelpers`]366pub struct CollectionHelpersOnMethodCall<T: Config>(PhantomData<*const T>);367impl<T: Config + pallet_nonfungible::Config + pallet_refungible::Config> OnMethodCall<T>368 for CollectionHelpersOnMethodCall<T>369{370 fn is_reserved(contract: &sp_core::H160) -> bool {371 contract == &T::ContractAddress::get()372 }373374 fn is_used(contract: &sp_core::H160) -> bool {375 contract == &T::ContractAddress::get()376 }377378 fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {379 if handle.code_address() != T::ContractAddress::get() {380 return None;381 }382383 let helpers =384 EvmCollectionHelpers::<T>(SubstrateRecorder::<T>::new(handle.remaining_gas()));385 pallet_evm_coder_substrate::call(handle, helpers)386 }387388 fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {389 (contract == &T::ContractAddress::get())390 .then(|| include_bytes!("./stubs/CollectionHelpers.raw").to_vec())391 }392}393394generate_stubgen!(collection_helper_impl, CollectionHelpersCall<()>, true);395generate_stubgen!(collection_helper_iface, CollectionHelpersCall<()>, false);396397fn error_field_too_long(feild: &str, bound: usize) -> Error {398 Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))399}