git.delta.rocks / unique-network / refs/commits / c26909611524

difftreelog

CORE-346 Rewrite tokenURL as property

Trubnikov Sergey2022-05-26parent: #7ed3eb8.patch.diff
in: master

2 files changed

modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -21,13 +21,13 @@
 };
 use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
 use frame_support::BoundedVec;
-use up_data_structs::{TokenId, SchemaVersion, PropertyPermission, PropertyKeyPermission, Property};
+use up_data_structs::{TokenId, SchemaVersion, PropertyPermission, PropertyKeyPermission, Property, CollectionId, PropertyKey, CollectionPropertiesVec};
 use pallet_evm_coder_substrate::dispatch_to_evm;
 use sp_core::{H160, U256};
 use sp_std::vec::Vec;
 use pallet_common::{
 	erc::{CommonEvmHandler, PrecompileResult, CollectionCall},
-	CollectionHandle,
+	CollectionHandle, CollectionPropertyPermissions,
 };
 use pallet_evm::account::CrossAccountId;
 use pallet_evm_coder_substrate::call;
@@ -158,6 +158,14 @@
 	/// Returns token's const_metadata
 	#[solidity(rename_selector = "tokenURI")]
 	fn token_uri(&self, token_id: uint256) -> Result<string> {
+		let key: string = "tokenURI".into(); //TODO: make static
+		let key: up_data_structs::PropertyKey = key.into_bytes().try_into()
+			.map_err(|_| Error::Revert("".into()))?;
+		let permission = get_permission::<T>(self.id, &key)?;
+		if !permission.collection_admin {
+			return Err("Operation is not allowed".into());
+		}
+
 		self.consume_store_reads(1)?;
 		let _token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
 		Ok(string::from_utf8_lossy(
@@ -350,6 +358,14 @@
 		token_id: uint256,
 		token_uri: string,
 	) -> Result<bool> {
+		let key: string = "tokenURI".into(); //TODO: make static
+		let key: up_data_structs::PropertyKey = key.into_bytes().try_into()
+			.map_err(|_| Error::Revert("".into()))?;
+		let permission = get_permission::<T>(self.id, &key)?;
+		if !permission.collection_admin {
+			return Err("Operation is not allowed".into());
+		}
+
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = T::CrossAccountId::from_eth(to);
 		let token_id: u32 = token_id.try_into().map_err(|_| "amount overflow")?;
@@ -365,13 +381,18 @@
 			return Err("item id should be next".into());
 		}
 
-		todo!("token uri");
+		let mut properties = CollectionPropertiesVec::default();
+		properties.try_push(Property{
+			key,
+			value: token_uri.into_bytes().try_into()
+				.map_err(|_| "token uri is too long")?
+		}).map_err(|e| Error::Revert(alloc::format!("Can't add property: {:?}", e)))?;
 
 		<Pallet<T>>::create_item(
 			self,
 			&caller,
 			CreateItemData::<T> {
-				properties: BoundedVec::default(),
+				properties,
 				owner: to,
 			},
 			&budget,
@@ -386,6 +407,14 @@
 	}
 }
 
+fn get_permission<T: Config>(collection_id: CollectionId, key: &PropertyKey) -> Result<PropertyPermission> {
+	let token_property_permissions = CollectionPropertyPermissions::<T>::try_get(collection_id)
+		.map_err(|_| Error::Revert("No permissions for collection".into()))?;
+	Ok(token_property_permissions.get(key)
+		.map(|p| p.clone())
+		.ok_or_else(|| Error::Revert("No permission for tokenURI".into()))?)
+}
+
 #[solidity_interface(name = "ERC721UniqueExtensions")]
 impl<T: Config> NonfungibleHandle<T> {
 	#[weight(<SelfWeightOf<T>>::transfer())]
modifiedpallets/unique/src/eth/mod.rsdiffbeforeafterboth
before · pallets/unique/src/eth/mod.rs
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/>.1617pub mod evm_collection {18	use core::marker::PhantomData;19	use evm_coder::{execution::*, generate_stubgen, solidity_interface, types::*, ToLog};20	use ethereum as _;21	use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};22	use pallet_evm::{OnMethodCall, PrecompileResult, account::CrossAccountId, Pallet as PalletEvm};23	use up_data_structs::{24		CreateCollectionData, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,25		MAX_COLLECTION_NAME_LENGTH,26	};27	use frame_support::traits::Get;28	use sp_core::H160;29	use pallet_common::CollectionById;30	31	use sp_std::vec::Vec;32	use alloc::format;33	34	pub trait Config:35		frame_system::Config36		+ pallet_evm_coder_substrate::Config37		+ pallet_evm::account::Config38		+ pallet_nonfungible::Config39	{40		type ContractAddress: Get<H160>;41	}4243	struct EvmCollectionHelper<T: Config>(SubstrateRecorder<T>);44	impl<T: Config> WithRecorder<T> for EvmCollectionHelper<T> {45		fn recorder(&self) -> &SubstrateRecorder<T> {46			&self.047		}48	49		fn into_recorder(self) -> SubstrateRecorder<T> {50			self.051		}52	}5354	#[solidity_interface(name = "CollectionHelper")]55	impl<T: Config> EvmCollectionHelper<T> {56		fn create_721_collection(57			&self,58			caller: caller,59			name: string,60			description: string,61			token_prefix: string,62		) -> Result<address> {63			let caller = T::CrossAccountId::from_eth(caller);64			let name = name65				.encode_utf16()66				.collect::<Vec<u16>>()67				.try_into()68				.map_err(|_| error_feild_too_long(stringify!(name), MAX_COLLECTION_NAME_LENGTH))?;69			let description = description70				.encode_utf16()71				.collect::<Vec<u16>>()72				.try_into()73				.map_err(|_| {74					error_feild_too_long(stringify!(description), MAX_COLLECTION_DESCRIPTION_LENGTH)75				})?;76			let token_prefix = token_prefix77				.into_bytes()78				.try_into()79				.map_err(|_| error_feild_too_long(stringify!(token_prefix), MAX_TOKEN_PREFIX_LENGTH))?;80	81			let data = CreateCollectionData {82				name,83				description,84				token_prefix,85				..Default::default()86			};87	88			let collection_id =89				<pallet_nonfungible::Pallet<T>>::init_collection(caller.as_sub().clone(), data)90					.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;91	92			let address = pallet_common::eth::collection_id_to_address(collection_id);93			<PalletEvm<T>>::deposit_log(94				EthCollectionEvent::CollectionCreated {95					owner: *caller.as_eth(),96					collection_id: address,97				}98				.to_log(address),99			);100			Ok(address)101		}102103		fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {104			if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {105				let collection_id = id;106				return Ok(<CollectionById<T>>::contains_key(collection_id));107			}108109			Ok(false)110		}111	}112	113	#[derive(ToLog)]114	pub enum EthCollectionEvent {115		CollectionCreated {116			#[indexed]117			owner: address,118			#[indexed]119			collection_id: address,120		},121	}122123	pub struct CollectionHelperOnMethodCall<T: Config>(PhantomData<*const T>);124	impl<T: Config> OnMethodCall<T> for CollectionHelperOnMethodCall<T> {125		fn is_reserved(contract: &sp_core::H160) -> bool {126			contract == &T::ContractAddress::get()127		}128	129		fn is_used(contract: &sp_core::H160) -> bool {130			contract == &T::ContractAddress::get()131		}132	133		fn call(134			source: &sp_core::H160,135			target: &sp_core::H160,136			gas_left: u64,137			input: &[u8],138			value: sp_core::U256,139		) -> Option<PrecompileResult> {140			if target != &T::ContractAddress::get() {141				return None;142			}143	144			let helpers = EvmCollectionHelper::<T>(SubstrateRecorder::<T>::new(gas_left));145			pallet_evm_coder_substrate::call(*source, helpers, value, input)146		}147	148		fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {149			(contract == &T::ContractAddress::get())150				.then(|| include_bytes!("./stubs/CollectionHelper.raw").to_vec())151		}152	}153	154	generate_stubgen!(collection_helper_impl, CollectionHelperCall<()>, true);155	generate_stubgen!(collection_helper_iface, CollectionHelperCall<()>, false);156157	fn error_feild_too_long(feild: &str, bound: u32) -> Error {158		Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))159	}160}
after · pallets/unique/src/eth/mod.rs
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/>.1617pub mod evm_collection {18	use core::marker::PhantomData;19	use evm_coder::{execution::*, generate_stubgen, solidity_interface, types::*, ToLog};20	use ethereum as _;21	use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};22	use pallet_evm::{OnMethodCall, PrecompileResult, account::CrossAccountId, Pallet as PalletEvm};23	use up_data_structs::{24		CreateCollectionData, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,25		MAX_COLLECTION_NAME_LENGTH,26	};27	use frame_support::traits::Get;28	use sp_core::H160;29	use pallet_common::CollectionById;30	31	use sp_std::vec::Vec;32	use alloc::format;33	34	pub trait Config:35		frame_system::Config36		+ pallet_evm_coder_substrate::Config37		+ pallet_evm::account::Config38		+ pallet_nonfungible::Config39	{40		type ContractAddress: Get<H160>;41	}4243	struct EvmCollectionHelper<T: Config>(SubstrateRecorder<T>);44	impl<T: Config> WithRecorder<T> for EvmCollectionHelper<T> {45		fn recorder(&self) -> &SubstrateRecorder<T> {46			&self.047		}48	49		fn into_recorder(self) -> SubstrateRecorder<T> {50			self.051		}52	}5354	#[solidity_interface(name = "CollectionHelper")]55	impl<T: Config> EvmCollectionHelper<T> {56		fn create_721_collection(57			&self,58			caller: caller,59			name: string,60			description: string,61			token_prefix: string,62		) -> Result<address> {63			let caller = T::CrossAccountId::from_eth(caller);64			let name = name65				.encode_utf16()66				.collect::<Vec<u16>>()67				.try_into()68				.map_err(|_| error_feild_too_long(stringify!(name), MAX_COLLECTION_NAME_LENGTH))?;69			let description = description70				.encode_utf16()71				.collect::<Vec<u16>>()72				.try_into()73				.map_err(|_| {74					error_feild_too_long(stringify!(description), MAX_COLLECTION_DESCRIPTION_LENGTH)75				})?;76			let token_prefix = token_prefix77				.into_bytes()78				.try_into()79				.map_err(|_| error_feild_too_long(stringify!(token_prefix), MAX_TOKEN_PREFIX_LENGTH))?;80	81			let key: string = "tokenURI".into(); //TODO: make static82			let key: up_data_structs::PropertyKey = key.into_bytes().try_into().map_err(|_| Error::Revert("".into()))?;83			let permission = up_data_structs::PropertyPermission {84				mutable: true,85				collection_admin: true,86				token_owner: false,87			};88			let mut token_property_permissions = up_data_structs::CollectionPropertiesPermissionsVec::default();89			token_property_permissions.try_push(up_data_structs::PropertyKeyPermission{90				key,91				permission,92			}).map_err(|e| Error::Revert(format!("{:?}", e)))?;9394			let data = CreateCollectionData {95				name,96				description,97				token_prefix,98				token_property_permissions,99				..Default::default()100			};101	102			let collection_id =103				<pallet_nonfungible::Pallet<T>>::init_collection(caller.as_sub().clone(), data)104					.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;105	106			let address = pallet_common::eth::collection_id_to_address(collection_id);107			<PalletEvm<T>>::deposit_log(108				EthCollectionEvent::CollectionCreated {109					owner: *caller.as_eth(),110					collection_id: address,111				}112				.to_log(address),113			);114			Ok(address)115		}116117		fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {118			if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {119				let collection_id = id;120				return Ok(<CollectionById<T>>::contains_key(collection_id));121			}122123			Ok(false)124		}125	}126	127	#[derive(ToLog)]128	pub enum EthCollectionEvent {129		CollectionCreated {130			#[indexed]131			owner: address,132			#[indexed]133			collection_id: address,134		},135	}136137	pub struct CollectionHelperOnMethodCall<T: Config>(PhantomData<*const T>);138	impl<T: Config> OnMethodCall<T> for CollectionHelperOnMethodCall<T> {139		fn is_reserved(contract: &sp_core::H160) -> bool {140			contract == &T::ContractAddress::get()141		}142	143		fn is_used(contract: &sp_core::H160) -> bool {144			contract == &T::ContractAddress::get()145		}146	147		fn call(148			source: &sp_core::H160,149			target: &sp_core::H160,150			gas_left: u64,151			input: &[u8],152			value: sp_core::U256,153		) -> Option<PrecompileResult> {154			if target != &T::ContractAddress::get() {155				return None;156			}157	158			let helpers = EvmCollectionHelper::<T>(SubstrateRecorder::<T>::new(gas_left));159			pallet_evm_coder_substrate::call(*source, helpers, value, input)160		}161	162		fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {163			(contract == &T::ContractAddress::get())164				.then(|| include_bytes!("./stubs/CollectionHelper.raw").to_vec())165		}166	}167	168	generate_stubgen!(collection_helper_impl, CollectionHelperCall<()>, true);169	generate_stubgen!(collection_helper_iface, CollectionHelperCall<()>, false);170171	fn error_feild_too_long(feild: &str, bound: u32) -> Error {172		Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))173	}174}