difftreelog
chore code review requests
in: master
8 files changed
pallets/common/src/erc.rsdiffbeforeafterboth--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -709,9 +709,6 @@
/// Value "1" ERC721 metadata supported.
pub const ERC721_METADATA_SUPPORTED: &[u8] = b"1";
- /// Value "0" ERC721 metadata supported.
- pub const ERC721_METADATA_UNSUPPORTED: &[u8] = b"0";
-
/// Value for [`ERC721_METADATA`].
pub fn erc721() -> up_data_structs::PropertyValue {
property_value_from_bytes(ERC721_METADATA).expect(EXPECT_CONVERT_ERROR)
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_interface, solidity, weight, types::*};22use frame_support::traits::Get;23use pallet_common::{24 CollectionById,25 dispatch::CollectionDispatch,26 erc::{27 CollectionHelpersEvents,28 static_property::{key, value as property_value},29 },30};31use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder};32use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};33use up_data_structs::{34 CollectionName, CollectionDescription, CollectionTokenPrefix, CreateCollectionData,35 CollectionMode, PropertyValue,36};3738use crate::{Config, SelfWeightOf, weights::WeightInfo};3940use sp_std::vec::Vec;41use alloc::format;4243/// See [`CollectionHelpersCall`]44pub struct EvmCollectionHelpers<T: Config>(SubstrateRecorder<T>);45impl<T: Config> WithRecorder<T> for EvmCollectionHelpers<T> {46 fn recorder(&self) -> &SubstrateRecorder<T> {47 &self.048 }4950 fn into_recorder(self) -> SubstrateRecorder<T> {51 self.052 }53}5455fn convert_data<T: Config>(56 caller: caller,57 name: string,58 description: string,59 token_prefix: string,60 base_uri: string,61) -> Result<(62 T::CrossAccountId,63 CollectionName,64 CollectionDescription,65 CollectionTokenPrefix,66 PropertyValue,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 let base_uri_value = base_uri85 .into_bytes()86 .try_into()87 .map_err(|_| error_field_too_long(stringify!(token_prefix), PropertyValue::bound()))?;88 Ok((caller, name, description, token_prefix, base_uri_value))89}9091fn make_data<T: Config>(92 name: CollectionName,93 mode: CollectionMode,94 description: CollectionDescription,95 token_prefix: CollectionTokenPrefix,96 base_uri_value: PropertyValue,97 add_properties: bool,98) -> Result<CreateCollectionData<T::AccountId>> {99 let mut properties = up_data_structs::CollectionPropertiesVec::default();100 let mut token_property_permissions =101 up_data_structs::CollectionPropertiesPermissionsVec::default();102103 token_property_permissions104 .try_push(up_data_structs::PropertyKeyPermission {105 key: key::url(),106 permission: up_data_structs::PropertyPermission {107 mutable: false,108 collection_admin: true,109 token_owner: false,110 },111 })112 .map_err(|e| Error::Revert(format!("{:?}", e)))?;113114 if add_properties {115 token_property_permissions116 .try_push(up_data_structs::PropertyKeyPermission {117 key: key::suffix(),118 permission: up_data_structs::PropertyPermission {119 mutable: true,120 collection_admin: true,121 token_owner: false,122 },123 })124 .map_err(|e| Error::Revert(format!("{:?}", e)))?;125126 token_property_permissions127 .try_push(up_data_structs::PropertyKeyPermission {128 key: key::url(),129 permission: up_data_structs::PropertyPermission {130 mutable: true,131 collection_admin: true,132 token_owner: false,133 },134 })135 .map_err(|e| Error::Revert(format!("{:?}", e)))?;136137 properties138 .try_push(up_data_structs::Property {139 key: key::schema_name(),140 value: property_value::erc721(),141 })142 .map_err(|e| Error::Revert(format!("{:?}", e)))?;143144 properties145 .try_push(up_data_structs::Property {146 key: key::schema_version(),147 value: property_value::schema_version(),148 })149 .map_err(|e| Error::Revert(format!("{:?}", e)))?;150151 properties152 .try_push(up_data_structs::Property {153 key: key::erc721_metadata(),154 value: property_value::erc721_metadata_supported(),155 })156 .map_err(|e| Error::Revert(format!("{:?}", e)))?;157158 if !base_uri_value.is_empty() {159 properties160 .try_push(up_data_structs::Property {161 key: key::base_uri(),162 value: base_uri_value,163 })164 .map_err(|e| Error::Revert(format!("{:?}", e)))?;165 }166 }167168 let data = CreateCollectionData {169 name,170 mode,171 description,172 token_prefix,173 token_property_permissions,174 properties,175 ..Default::default()176 };177 Ok(data)178}179180fn create_refungible_collection_internal<181 T: Config + pallet_nonfungible::Config + pallet_refungible::Config,182>(183 caller: caller,184 value: value,185 name: string,186 description: string,187 token_prefix: string,188 base_uri: string,189 add_properties: bool,190) -> Result<address> {191 let (caller, name, description, token_prefix, base_uri_value) =192 convert_data::<T>(caller, name, description, token_prefix, base_uri)?;193 let data = make_data::<T>(194 name,195 CollectionMode::ReFungible,196 description,197 token_prefix,198 base_uri_value,199 add_properties,200 )?;201 check_sent_amount_equals_collection_creation_price::<T>(value)?;202 let collection_helpers_address =203 T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());204205 let collection_id =206 T::CollectionDispatch::create(caller.clone(), collection_helpers_address, data)207 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;208 let address = pallet_common::eth::collection_id_to_address(collection_id);209 Ok(address)210}211212fn check_sent_amount_equals_collection_creation_price<T: Config>(value: value) -> Result<()> {213 let value = value.as_u128();214 let creation_price: u128 = T::CollectionCreationPrice::get()215 .try_into()216 .map_err(|_| ()) // workaround for `expect` requiring `Debug` trait217 .expect("Collection creation price should be convertible to u128");218 if value != creation_price {219 return Err(format!(220 "Sent amount not equals to collection creation price ({0})",221 creation_price222 )223 .into());224 }225 Ok(())226}227228/// @title Contract, which allows users to operate with collections229#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents))]230impl<T> EvmCollectionHelpers<T>231where232 T: Config + pallet_common::Config + pallet_nonfungible::Config + pallet_refungible::Config,233{234 /// Create an NFT collection235 /// @param name Name of the collection236 /// @param description Informative description of the collection237 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications238 /// @return address Address of the newly created collection239 #[weight(<SelfWeightOf<T>>::create_collection())]240 #[solidity(rename_selector = "createNFTCollection")]241 fn create_nft_collection(242 &mut self,243 caller: caller,244 value: value,245 name: string,246 description: string,247 token_prefix: string,248 ) -> Result<address> {249 let (caller, name, description, token_prefix, _base_uri_value) =250 convert_data::<T>(caller, name, description, token_prefix, "".into())?;251 let data = make_data::<T>(252 name,253 CollectionMode::NFT,254 description,255 token_prefix,256 Default::default(),257 false,258 )?;259 check_sent_amount_equals_collection_creation_price::<T>(value)?;260 let collection_helpers_address =261 T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());262 let collection_id = T::CollectionDispatch::create(caller, collection_helpers_address, data)263 .map_err(dispatch_to_evm::<T>)?;264265 let address = pallet_common::eth::collection_id_to_address(collection_id);266 Ok(address)267 }268 /// Create an NFT collection269 /// @param name Name of the collection270 /// @param description Informative description of the collection271 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications272 /// @return address Address of the newly created collection273 #[weight(<SelfWeightOf<T>>::create_collection())]274 #[deprecated(note = "mathod was renamed to `create_nft_collection`, prefer it instead")]275 fn create_nonfungible_collection(276 &mut self,277 caller: caller,278 value: value,279 name: string,280 description: string,281 token_prefix: string,282 ) -> Result<address> {283 self.create_nft_collection(caller, value, name, description, token_prefix)284 }285286 #[weight(<SelfWeightOf<T>>::create_collection())]287 #[solidity(rename_selector = "createERC721MetadataCompatibleNFTCollection")]288 fn create_nonfungible_collection_with_properties(289 &mut self,290 caller: caller,291 value: value,292 name: string,293 description: string,294 token_prefix: string,295 base_uri: string,296 ) -> Result<address> {297 let (caller, name, description, token_prefix, base_uri_value) =298 convert_data::<T>(caller, name, description, token_prefix, base_uri)?;299 let data = make_data::<T>(300 name,301 CollectionMode::NFT,302 description,303 token_prefix,304 base_uri_value,305 true,306 )?;307 check_sent_amount_equals_collection_creation_price::<T>(value)?;308 let collection_helpers_address =309 T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());310 let collection_id = T::CollectionDispatch::create(caller, collection_helpers_address, data)311 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;312313 let address = pallet_common::eth::collection_id_to_address(collection_id);314 Ok(address)315 }316317 #[weight(<SelfWeightOf<T>>::create_collection())]318 #[solidity(rename_selector = "createRFTCollection")]319 fn create_rft_collection(320 &mut self,321 caller: caller,322 value: value,323 name: string,324 description: string,325 token_prefix: string,326 ) -> Result<address> {327 create_refungible_collection_internal::<T>(328 caller,329 value,330 name,331 description,332 token_prefix,333 Default::default(),334 false,335 )336 }337338 #[weight(<SelfWeightOf<T>>::create_collection())]339 #[solidity(rename_selector = "createERC721MetadataCompatibleRFTCollection")]340 fn create_refungible_collection_with_properties(341 &mut self,342 caller: caller,343 value: value,344 name: string,345 description: string,346 token_prefix: string,347 base_uri: string,348 ) -> Result<address> {349 create_refungible_collection_internal::<T>(350 caller,351 value,352 name,353 description,354 token_prefix,355 base_uri,356 true,357 )358 }359360 /// Check if a collection exists361 /// @param collectionAddress Address of the collection in question362 /// @return bool Does the collection exist?363 fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {364 if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {365 let collection_id = id;366 return Ok(<CollectionById<T>>::contains_key(collection_id));367 }368369 Ok(false)370 }371372 fn collection_creation_fee(&self) -> Result<value> {373 let price: u128 = T::CollectionCreationPrice::get()374 .try_into()375 .map_err(|_| ()) // workaround for `expect` requiring `Debug` trait376 .expect("Collection creation price should be convertible to u128");377 Ok(price.into())378 }379}380381/// Implements [`OnMethodCall`], which delegates call to [`EvmCollectionHelpers`]382pub struct CollectionHelpersOnMethodCall<T: Config>(PhantomData<*const T>);383impl<T: Config + pallet_nonfungible::Config + pallet_refungible::Config> OnMethodCall<T>384 for CollectionHelpersOnMethodCall<T>385{386 fn is_reserved(contract: &sp_core::H160) -> bool {387 contract == &T::ContractAddress::get()388 }389390 fn is_used(contract: &sp_core::H160) -> bool {391 contract == &T::ContractAddress::get()392 }393394 fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {395 if handle.code_address() != T::ContractAddress::get() {396 return None;397 }398399 let helpers =400 EvmCollectionHelpers::<T>(SubstrateRecorder::<T>::new(handle.remaining_gas()));401 pallet_evm_coder_substrate::call(handle, helpers)402 }403404 fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {405 (contract == &T::ContractAddress::get())406 .then(|| include_bytes!("./stubs/CollectionHelpers.raw").to_vec())407 }408}409410generate_stubgen!(collection_helper_impl, CollectionHelpersCall<()>, true);411generate_stubgen!(collection_helper_iface, CollectionHelpersCall<()>, false);412413fn error_field_too_long(feild: &str, bound: usize) -> Error {414 Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))415}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_interface, solidity, weight, types::*};22use frame_support::traits::Get;23use pallet_common::{24 CollectionById,25 dispatch::CollectionDispatch,26 erc::{27 CollectionHelpersEvents,28 static_property::{key, value as property_value},29 },30};31use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder};32use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};33use up_data_structs::{34 CollectionName, CollectionDescription, CollectionTokenPrefix, CreateCollectionData,35 CollectionMode, PropertyValue,36};3738use crate::{Config, SelfWeightOf, weights::WeightInfo};3940use sp_std::vec::Vec;41use alloc::format;4243/// See [`CollectionHelpersCall`]44pub struct EvmCollectionHelpers<T: Config>(SubstrateRecorder<T>);45impl<T: Config> WithRecorder<T> for EvmCollectionHelpers<T> {46 fn recorder(&self) -> &SubstrateRecorder<T> {47 &self.048 }4950 fn into_recorder(self) -> SubstrateRecorder<T> {51 self.052 }53}5455fn convert_data<T: Config>(56 caller: caller,57 name: string,58 description: string,59 token_prefix: string,60 base_uri: string,61) -> Result<(62 T::CrossAccountId,63 CollectionName,64 CollectionDescription,65 CollectionTokenPrefix,66 PropertyValue,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 let base_uri_value = base_uri85 .into_bytes()86 .try_into()87 .map_err(|_| error_field_too_long(stringify!(token_prefix), PropertyValue::bound()))?;88 Ok((caller, name, description, token_prefix, base_uri_value))89}9091fn make_data<T: Config>(92 name: CollectionName,93 mode: CollectionMode,94 description: CollectionDescription,95 token_prefix: CollectionTokenPrefix,96 base_uri_value: PropertyValue,97 add_properties: bool,98) -> Result<CreateCollectionData<T::AccountId>> {99 let mut properties = up_data_structs::CollectionPropertiesVec::default();100 let mut token_property_permissions =101 up_data_structs::CollectionPropertiesPermissionsVec::default();102103 token_property_permissions104 .try_push(up_data_structs::PropertyKeyPermission {105 key: key::url(),106 permission: up_data_structs::PropertyPermission {107 mutable: true,108 collection_admin: true,109 token_owner: false,110 },111 })112 .map_err(|e| Error::Revert(format!("{:?}", e)))?;113114 if add_properties {115 token_property_permissions116 .try_push(up_data_structs::PropertyKeyPermission {117 key: key::suffix(),118 permission: up_data_structs::PropertyPermission {119 mutable: true,120 collection_admin: true,121 token_owner: false,122 },123 })124 .map_err(|e| Error::Revert(format!("{:?}", e)))?;125126 properties127 .try_push(up_data_structs::Property {128 key: key::schema_name(),129 value: property_value::erc721(),130 })131 .map_err(|e| Error::Revert(format!("{:?}", e)))?;132133 properties134 .try_push(up_data_structs::Property {135 key: key::schema_version(),136 value: property_value::schema_version(),137 })138 .map_err(|e| Error::Revert(format!("{:?}", e)))?;139140 properties141 .try_push(up_data_structs::Property {142 key: key::erc721_metadata(),143 value: property_value::erc721_metadata_supported(),144 })145 .map_err(|e| Error::Revert(format!("{:?}", e)))?;146147 if !base_uri_value.is_empty() {148 properties149 .try_push(up_data_structs::Property {150 key: key::base_uri(),151 value: base_uri_value,152 })153 .map_err(|e| Error::Revert(format!("{:?}", e)))?;154 }155 }156157 let data = CreateCollectionData {158 name,159 mode,160 description,161 token_prefix,162 token_property_permissions,163 properties,164 ..Default::default()165 };166 Ok(data)167}168169fn create_refungible_collection_internal<170 T: Config + pallet_nonfungible::Config + pallet_refungible::Config,171>(172 caller: caller,173 value: value,174 name: string,175 description: string,176 token_prefix: string,177 base_uri: string,178 add_properties: bool,179) -> Result<address> {180 let (caller, name, description, token_prefix, base_uri_value) =181 convert_data::<T>(caller, name, description, token_prefix, base_uri)?;182 let data = make_data::<T>(183 name,184 CollectionMode::ReFungible,185 description,186 token_prefix,187 base_uri_value,188 add_properties,189 )?;190 check_sent_amount_equals_collection_creation_price::<T>(value)?;191 let collection_helpers_address =192 T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());193194 let collection_id =195 T::CollectionDispatch::create(caller.clone(), collection_helpers_address, data)196 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;197 let address = pallet_common::eth::collection_id_to_address(collection_id);198 Ok(address)199}200201fn check_sent_amount_equals_collection_creation_price<T: Config>(value: value) -> Result<()> {202 let value = value.as_u128();203 let creation_price: u128 = T::CollectionCreationPrice::get()204 .try_into()205 .map_err(|_| ()) // workaround for `expect` requiring `Debug` trait206 .expect("Collection creation price should be convertible to u128");207 if value != creation_price {208 return Err(format!(209 "Sent amount not equals to collection creation price ({0})",210 creation_price211 )212 .into());213 }214 Ok(())215}216217/// @title Contract, which allows users to operate with collections218#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents))]219impl<T> EvmCollectionHelpers<T>220where221 T: Config + pallet_common::Config + pallet_nonfungible::Config + pallet_refungible::Config,222{223 /// Create an NFT collection224 /// @param name Name of the collection225 /// @param description Informative description of the collection226 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications227 /// @return address Address of the newly created collection228 #[weight(<SelfWeightOf<T>>::create_collection())]229 #[solidity(rename_selector = "createNFTCollection")]230 fn create_nft_collection(231 &mut self,232 caller: caller,233 value: value,234 name: string,235 description: string,236 token_prefix: string,237 ) -> Result<address> {238 let (caller, name, description, token_prefix, _base_uri_value) =239 convert_data::<T>(caller, name, description, token_prefix, "".into())?;240 let data = make_data::<T>(241 name,242 CollectionMode::NFT,243 description,244 token_prefix,245 Default::default(),246 false,247 )?;248 check_sent_amount_equals_collection_creation_price::<T>(value)?;249 let collection_helpers_address =250 T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());251 let collection_id = T::CollectionDispatch::create(caller, collection_helpers_address, data)252 .map_err(dispatch_to_evm::<T>)?;253254 let address = pallet_common::eth::collection_id_to_address(collection_id);255 Ok(address)256 }257 /// Create an NFT collection258 /// @param name Name of the collection259 /// @param description Informative description of the collection260 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications261 /// @return address Address of the newly created collection262 #[weight(<SelfWeightOf<T>>::create_collection())]263 #[deprecated(note = "mathod was renamed to `create_nft_collection`, prefer it instead")]264 fn create_nonfungible_collection(265 &mut self,266 caller: caller,267 value: value,268 name: string,269 description: string,270 token_prefix: string,271 ) -> Result<address> {272 self.create_nft_collection(caller, value, name, description, token_prefix)273 }274275 #[weight(<SelfWeightOf<T>>::create_collection())]276 #[solidity(rename_selector = "createERC721MetadataCompatibleNFTCollection")]277 fn create_nonfungible_collection_with_properties(278 &mut self,279 caller: caller,280 value: value,281 name: string,282 description: string,283 token_prefix: string,284 base_uri: string,285 ) -> Result<address> {286 let (caller, name, description, token_prefix, base_uri_value) =287 convert_data::<T>(caller, name, description, token_prefix, base_uri)?;288 let data = make_data::<T>(289 name,290 CollectionMode::NFT,291 description,292 token_prefix,293 base_uri_value,294 true,295 )?;296 check_sent_amount_equals_collection_creation_price::<T>(value)?;297 let collection_helpers_address =298 T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());299 let collection_id = T::CollectionDispatch::create(caller, collection_helpers_address, data)300 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;301302 let address = pallet_common::eth::collection_id_to_address(collection_id);303 Ok(address)304 }305306 #[weight(<SelfWeightOf<T>>::create_collection())]307 #[solidity(rename_selector = "createRFTCollection")]308 fn create_rft_collection(309 &mut self,310 caller: caller,311 value: value,312 name: string,313 description: string,314 token_prefix: string,315 ) -> Result<address> {316 create_refungible_collection_internal::<T>(317 caller,318 value,319 name,320 description,321 token_prefix,322 Default::default(),323 false,324 )325 }326327 #[weight(<SelfWeightOf<T>>::create_collection())]328 #[solidity(rename_selector = "createERC721MetadataCompatibleRFTCollection")]329 fn create_refungible_collection_with_properties(330 &mut self,331 caller: caller,332 value: value,333 name: string,334 description: string,335 token_prefix: string,336 base_uri: string,337 ) -> Result<address> {338 create_refungible_collection_internal::<T>(339 caller,340 value,341 name,342 description,343 token_prefix,344 base_uri,345 true,346 )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}tests/src/deprecated-helpers/helpers.tsdiffbeforeafterboth--- a/tests/src/deprecated-helpers/helpers.ts
+++ b/tests/src/deprecated-helpers/helpers.ts
@@ -433,7 +433,6 @@
mode: {type: 'NFT'},
name: 'name',
tokenPrefix: 'prefix',
- properties: [{key: 'ERC721Metadata', value: '1'}],
};
export async function
tests/src/eth/base.test.tsdiffbeforeafterboth--- a/tests/src/eth/base.test.ts
+++ b/tests/src/eth/base.test.ts
@@ -80,7 +80,7 @@
await usingEthPlaygrounds(async (helper, privateKey) => {
const donor = privateKey('//Alice');
const [alice] = await helper.arrange.createAccounts([10n], donor);
- ({collectionId: collection} = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}));
+ ({collectionId: collection} = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test', properties: [{key: 'ERC721Metadata', value: '1'}]}));
minter = helper.eth.createAccount();
});
});
tests/src/eth/nonFungible.test.tsdiffbeforeafterboth--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -501,7 +501,7 @@
itEth('Returns collection name', async ({helper}) => {
const caller = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.nft.mintCollection(alice, {name: 'oh River', tokenPrefix: 'CHANGE'});
+ const collection = await helper.nft.mintCollection(alice, {name: 'oh River', tokenPrefix: 'CHANGE', properties: [{key: 'ERC721Metadata', value: '1'}]});
const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
const name = await contract.methods.name().call();
@@ -510,7 +510,7 @@
itEth('Returns symbol name', async ({helper}) => {
const caller = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.nft.mintCollection(alice, {name: 'oh River', tokenPrefix: 'CHANGE'});
+ const collection = await helper.nft.mintCollection(alice, {name: 'oh River', tokenPrefix: 'CHANGE', properties: [{key: 'ERC721Metadata', value: '1'}]});
const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
const symbol = await contract.methods.symbol().call();
tests/src/eth/reFungible.test.tsdiffbeforeafterboth--- a/tests/src/eth/reFungible.test.ts
+++ b/tests/src/eth/reFungible.test.ts
@@ -377,7 +377,7 @@
itEth('Returns collection name', async ({helper}) => {
const caller = helper.eth.createAccount();
- const collection = await helper.rft.mintCollection(alice, {name: 'Leviathan', tokenPrefix: '11'});
+ const collection = await helper.rft.mintCollection(alice, {name: 'Leviathan', tokenPrefix: '11', properties: [{key: 'ERC721Metadata', value: '1'}]});
const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'rft', caller);
const name = await contract.methods.name().call();
@@ -386,7 +386,7 @@
itEth('Returns symbol name', async ({helper}) => {
const caller = await helper.eth.createAccountWithBalance(donor);
- const {collectionId} = await helper.rft.mintCollection(alice, {name: 'Leviathan', tokenPrefix: '12'});
+ const {collectionId} = await helper.rft.mintCollection(alice, {name: 'Leviathan', tokenPrefix: '12', properties: [{key: 'ERC721Metadata', value: '1'}]});
const contract = helper.ethNativeContract.collectionById(collectionId, 'rft', caller);
const symbol = await contract.methods.symbol().call();
expect(symbol).to.equal('12');
tests/src/nesting/properties.test.tsdiffbeforeafterboth--- a/tests/src/nesting/properties.test.ts
+++ b/tests/src/nesting/properties.test.ts
@@ -35,7 +35,7 @@
expect(collectionOption).is.not.null;
let collection = collectionOption;
expect(collection.tokenPropertyPermissions).to.be.empty;
- expect(collection.properties).to.be.deep.equal([{key: 'ERC721Metadata', value: '1'}]);
+ expect(collection.properties).to.be.empty;
const propertyPermissions = [
{key: 'mindgame', permission: {collectionAdmin: true, mutable: false, tokenOwner: true}},
@@ -44,7 +44,6 @@
await expect(await baseCollection.setTokenPropertyPermissions(alice, propertyPermissions)).to.be.true;
const collectionProperties = [
- {key: 'ERC721Metadata', value: '1'},
{key: 'black_hole', value: 'LIGO'},
{key: 'electron', value: 'come bond'},
];
@@ -80,10 +79,7 @@
itSub('Properties are initially empty', async ({helper}) => {
const collection = await helper.nft.mintCollection(alice);
const properties = await collection.getProperties();
- expect(properties).to.be.deep.equal([{
- 'key': 'ERC721Metadata',
- 'value': '1',
- }]);
+ expect(properties).to.be.empty;
});
async function testSetsPropertiesForCollection(collection: UniqueBaseCollection) {
@@ -201,10 +197,7 @@
.to.be.rejectedWith(/common\.NoPermission/);
const properties = await collection.getProperties();
- expect(properties).to.be.deep.equal([{
- 'key': 'ERC721Metadata',
- 'value': '1',
- }]);
+ expect(properties).to.be.empty;
}
itSub('Fails to set properties in a NFT collection if not its onwer/administrator', async ({helper}) => {
@@ -257,10 +250,7 @@
to.be.rejectedWith(/common\.PropertyLimitReached/);
const properties = await collection.getProperties();
- expect(properties).to.be.deep.equal([{
- 'key': 'ERC721Metadata',
- 'value': '1',
- }]);
+ expect(properties).to.be.empty;
}
itSub('Fails to set more properties than it is allowed (NFT)', async ({helper}) => {
tests/src/util/playgrounds/unique.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -1297,7 +1297,6 @@
async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueBaseCollection> {
collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object
collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};
- collectionOptions.properties = collectionOptions.properties || [{key: 'ERC721Metadata', value: '1'}];
for (const key of ['name', 'description', 'tokenPrefix']) {
if (typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);
}