difftreelog
CORE-346 Rewrite tokenURL as property
in: master
2 files changed
pallets/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())]
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/>.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}