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

difftreelog

feat add rmrk proxy nft minting

Daniel Shiposha2022-05-23parent: #c22e2cd.patch.diff
in: master

5 files changed

modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
22use up_data_structs::{22use up_data_structs::{
23 AccessMode, CollectionId, CustomDataLimit, TokenId, CreateCollectionData, CreateNftExData,23 AccessMode, CollectionId, CustomDataLimit, TokenId, CreateCollectionData, CreateNftExData,
24 mapping::TokenAddressMapping, NestingRule, budget::Budget, Property, PropertyPermission,24 mapping::TokenAddressMapping, NestingRule, budget::Budget, Property, PropertyPermission,
25 PropertyKey, PropertyKeyPermission, Properties, TrySetProperty,25 PropertyKey, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty,
26};26};
27use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};27use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};
28use pallet_common::{28use pallet_common::{
194 <TokenData<T>>::contains_key((collection.id, token))194 <TokenData<T>>::contains_key((collection.id, token))
195 }195 }
196
197 pub fn set_scoped_token_property(
198 collection: &CollectionHandle<T>,
199 token_id: TokenId,
200 scope: PropertyScope,
201 property: Property,
202 ) -> DispatchResult {
203 TokenProperties::<T>::try_mutate((collection.id, token_id), |properties| {
204 properties.try_scoped_set(scope, property.key, property.value)
205 })
206 .map_err(<CommonError<T>>::from)?;
207
208 Ok(())
209 }
210
211 pub fn set_scoped_token_properties(
212 collection: &CollectionHandle<T>,
213 token_id: TokenId,
214 scope: PropertyScope,
215 properties: impl Iterator<Item=Property>,
216 ) -> DispatchResult {
217 TokenProperties::<T>::try_mutate((collection.id, token_id), |stored_properties| {
218 stored_properties.try_scoped_set_from_iter(scope, properties)
219 })
220 .map_err(<CommonError<T>>::from)?;
221
222 Ok(())
223 }
224
225 pub fn current_token_id(collection: &CollectionHandle<T>) -> TokenId {
226 TokenId(<TokensMinted<T>>::get(collection.id))
227 }
196}228}
197229
198// unchecked calls skips any permission checks230// unchecked calls skips any permission checks
modifiedpallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth
1818
19use frame_support::{pallet_prelude::*, transactional, BoundedVec, dispatch::DispatchResult};19use frame_support::{pallet_prelude::*, transactional, BoundedVec, dispatch::DispatchResult};
20use frame_system::{pallet_prelude::*, ensure_signed};20use frame_system::{pallet_prelude::*, ensure_signed};
21use sp_runtime::{DispatchError, traits::StaticLookup};21use sp_runtime::{DispatchError, Permill, traits::StaticLookup};
22use sp_std::vec::Vec;
22use up_data_structs::*;23use up_data_structs::*;
23use pallet_common::{Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations};24use pallet_common::{Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations};
24use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle};25use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle};
69 issuer: T::AccountId,70 issuer: T::AccountId,
70 collection_id: RmrkCollectionId,71 collection_id: RmrkCollectionId,
71 },72 },
73 NftMinted {
74 owner: T::AccountId,
75 collection_id: RmrkCollectionId,
76 nft_id: RmrkNftId,
77 },
72 }78 }
7379
74 #[pallet::error]80 #[pallet::error]
75 pub enum Error<T> {81 pub enum Error<T> {
76 /* Unique-specific events */82 /* Unique-specific events */
77 CorruptedCollectionType,83 CorruptedCollectionType,
84 NftTypeEncodeError,
78 RmrkPropertyKeyIsTooLong,85 RmrkPropertyKeyIsTooLong,
79 RmrkPropertyValueIsTooLong,86 RmrkPropertyValueIsTooLong,
8087
81 /* RMRK compatible events */88 /* RMRK compatible events */
82 CollectionNotEmpty,89 CollectionNotEmpty,
83 NoAvailableCollectionId,90 NoAvailableCollectionId,
91 NoAvailableNftId,
84 CollectionUnknown,92 CollectionUnknown,
93 NoPermission,
94 CollectionFullOrLocked,
85 }95 }
8696
87 #[pallet::call]97 #[pallet::call]
147157
148 let unique_collection_id = collection_id.into();158 let unique_collection_id = collection_id.into();
149159
150 let collection = Self::get_nft_collection(unique_collection_id)?;160 let collection = Self::get_typed_nft_collection(unique_collection_id, CollectionType::Regular)?;
151
152 Self::check_collection_type(unique_collection_id, CollectionType::Regular)?;
153161
154 ensure!(collection.total_supply() == 0, <Error<T>>::CollectionNotEmpty);162 ensure!(collection.total_supply() == 0, <Error<T>>::CollectionNotEmpty);
155163
196 let sender = ensure_signed(origin)?;204 let sender = ensure_signed(origin)?;
197 let cross_sender = T::CrossAccountId::from_sub(sender.clone());205 let cross_sender = T::CrossAccountId::from_sub(sender.clone());
198206
199 let collection = Self::get_nft_collection(collection_id.into())?;207 let collection = Self::get_typed_nft_collection(
208 collection_id.into(),
209 CollectionType::Regular
210 )?;
200 collection.check_is_owner(&cross_sender)?;211 collection.check_is_owner(&cross_sender)?;
201212
210 Ok(())221 Ok(())
211 }222 }
223
224 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
225 #[transactional]
226 pub fn mint_nft(
227 origin: OriginFor<T>,
228 owner: T::AccountId,
229 collection_id: RmrkCollectionId,
230 recipient: Option<T::AccountId>,
231 royalty_amount: Option<Permill>,
232 metadata: RmrkString,
233 ) -> DispatchResult {
234 let sender = ensure_signed(origin)?;
235 let sender = T::CrossAccountId::from_sub(sender);
236 let cross_owner = T::CrossAccountId::from_sub(owner.clone());
237
238 let royalty_info = royalty_amount.map(|amount| rmrk::RoyaltyInfo {
239 recipient: recipient.unwrap_or_else(|| owner.clone()),
240 amount
241 });
242
243 let nft_id = Self::create_nft(
244 sender,
245 cross_owner,
246 collection_id.into(),
247 CollectionType::Regular,
248 NftType::Regular,
249 [
250 rmrk_property!(Config=T, RoyaltyInfo: royalty_info)?,
251 rmrk_property!(Config=T, Metadata: metadata)?,
252 rmrk_property!(Config=T, Equipped: false)?,
253 rmrk_property!(Config=T, ResourceCollection: None::<CollectionId>)?,
254 rmrk_property!(Config=T, ResourcePriorities: <Vec<u8>>::new())?,
255 ].into_iter()
256 )?;
257
258 Self::deposit_event(Event::NftMinted {
259 owner,
260 collection_id,
261 nft_id: nft_id.0
262 });
263
264 Ok(())
265 }
212 }266 }
213}267}
214268
215impl<T: Config> Pallet<T> {269impl<T: Config> Pallet<T> {
270 fn create_nft(
271 sender: T::CrossAccountId,
272 owner: T::CrossAccountId,
273 collection_id: CollectionId,
274 collection_type: CollectionType,
275 nft_type: NftType,
276 properties: impl Iterator<Item=Property>
277 ) -> Result<TokenId, DispatchError> {
278 let collection = Self::get_typed_nft_collection(
279 collection_id,
280 collection_type
281 )?;
282
283 let data = CreateNftExData {
284 const_data: nft_type.encode()
285 .try_into()
286 .map_err(|_| <Error<T>>::NftTypeEncodeError)?,
287 properties: BoundedVec::default(),
288 owner,
289 };
290
291 let budget = budget::Value::new(2);
292
293 <PalletNft<T>>::create_item(
294 &collection,
295 &sender,
296 data,
297 &budget,
298 ).map_err(|err| {
299 map_common_err_to_proxy!(
300 match err {
301 NoPermission => NoPermission,
302 CollectionTokenLimitExceeded => CollectionFullOrLocked
303 }
304 )
305 })?;
306
307 let nft_id = <PalletNft<T>>::current_token_id(&collection);
308
309 <PalletNft<T>>::set_scoped_token_properties(
310 &collection,
311 nft_id,
312 PropertyScope::Rmrk,
313 properties
314 )?;
315
316 Ok(nft_id)
317 }
318
216 fn change_collection_owner(319 fn change_collection_owner(
217 collection_id: CollectionId,320 collection_id: CollectionId,
218 collection_type: CollectionType,321 collection_type: CollectionType,
219 sender: T::AccountId,322 sender: T::AccountId,
220 new_owner: T::AccountId,323 new_owner: T::AccountId,
221 ) -> DispatchResult {324 ) -> DispatchResult {
222 let mut collection = Self::get_nft_collection(collection_id)?.into_inner();325 let mut collection = Self::get_typed_nft_collection(
326 collection_id,
327 collection_type
328 )?.into_inner();
223 collection.check_is_owner(&T::CrossAccountId::from_sub(sender))?;329 collection.check_is_owner(&T::CrossAccountId::from_sub(sender))?;
224
225 Self::check_collection_type(collection_id, collection_type)?;
226330
227 collection.owner = new_owner;331 collection.owner = new_owner;
228 collection.save()332 collection.save()
257 pub fn get_nft_property(collection_id: CollectionId, nft_id: TokenId, key: RmrkProperty) -> Result<PropertyValue, DispatchError> {361 pub fn get_nft_property(collection_id: CollectionId, nft_id: TokenId, key: RmrkProperty) -> Result<PropertyValue, DispatchError> {
258 let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))362 let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))
259 .get(&rmrk_property!(Config=T, key)?)363 .get(&rmrk_property!(Config=T, key)?)
260 .ok_or(<Error<T>>::CollectionUnknown)? // todo is that right?364 .ok_or(<Error<T>>::NoAvailableNftId)?
261 .clone();365 .clone();
262366
263 Ok(nft_property)367 Ok(nft_property)
270 Ok(())374 Ok(())
271 }375 }
376
377 fn get_typed_nft_collection(
378 collection_id: CollectionId,
379 collection_type: CollectionType
380 ) -> Result<NonfungibleHandle<T>, DispatchError> {
381 Self::check_collection_type(collection_id, collection_type)?;
382
383 Self::get_nft_collection(collection_id)
384 }
272}385}
273386
modifiedpallets/proxy-rmrk-core/src/misc.rsdiffbeforeafterboth
1use super::*;1use super::*;
2use codec::{Encode, Decode};2use codec::{Encode, Decode};
3use pallet_nonfungible::NonfungibleHandle;3use pallet_nonfungible::{NonfungibleHandle, ItemData};
44
5macro_rules! impl_rmrk_value {5macro_rules! impl_rmrk_value {
6 ($enum_name:path, decode_error: $error:ident) => {6 ($enum_name:path, decode_error: $error:ident) => {
7 impl IntoPropertyValue for $enum_name {
8 fn into_property_value(self) -> Result<PropertyValue, MiscError> {
9 self.encode()
10 .try_into()
11 .map_err(|_| MiscError::RmrkPropertyValueIsTooLong)
12 }
13 }
14
15 impl TryFrom<&PropertyValue> for $enum_name {7 impl TryFrom<&PropertyValue> for $enum_name {
16 type Error = MiscError;8 type Error = MiscError;
26 };18 };
27}19}
20
21#[macro_export]
22macro_rules! map_common_err_to_proxy {
23 (match $err:ident { $($common_err:ident => $proxy_err:ident),+ }) => {
24 $(
25 if $err == <CommonError<T>>::$common_err.into() {
26 return <Error<T>>::$proxy_err.into()
27 } else
28 )+ {
29 $err
30 }
31 };
32}
2833
29pub enum MiscError {34pub enum MiscError {
30 RmrkPropertyValueIsTooLong,35 RmrkPropertyValueIsTooLong,
57 fn into_property_value(self) -> Result<PropertyValue, MiscError>;62 fn into_property_value(self) -> Result<PropertyValue, MiscError>;
58}63}
5964
60impl<L: Get<u32>> IntoPropertyValue for BoundedVec<u8, L> {65impl<T: Encode> IntoPropertyValue for T {
61 fn into_property_value(self) -> Result<PropertyValue, MiscError> {66 fn into_property_value(self) -> Result<PropertyValue, MiscError> {
62 self.into_inner()67 self.encode()
63 .try_into()68 .try_into()
64 .map_err(|_| MiscError::RmrkPropertyValueIsTooLong)69 .map_err(|_| MiscError::RmrkPropertyValueIsTooLong)
65 }70 }
66}71}
72
73pub trait RmrkNft {
74 fn rmrk_nft_type(&self) -> Option<NftType>;
75}
76
77impl<CrossAccountId> RmrkNft for ItemData<CrossAccountId> {
78 fn rmrk_nft_type(&self) -> Option<NftType> {
79 let mut value = self.const_data.as_slice();
80
81 NftType::decode(&mut value).ok()
82 }
83}
6784
68#[derive(Encode, Decode, PartialEq, Eq)]85#[derive(Encode, Decode, PartialEq, Eq)]
69pub enum CollectionType {86pub enum CollectionType {
72 Base,89 Base,
73}90}
91
92#[derive(Encode, Decode, PartialEq, Eq)]
93pub enum NftType {
94 Regular,
95 Resource,
96 FixedPart,
97 SlotPart,
98 Theme
99}
74100
75impl_rmrk_value!(CollectionType, decode_error: CorruptedCollectionType);101impl_rmrk_value!(CollectionType, decode_error: CorruptedCollectionType);
76102
modifiedpallets/proxy-rmrk-core/src/property.rsdiffbeforeafterboth
4pub enum RmrkProperty {4pub enum RmrkProperty {
5 Metadata,5 Metadata,
6 CollectionType,6 CollectionType,
7 Recipient,
8 Royalty,7 RoyaltyInfo,
9 Equipped,8 Equipped,
10 ResourceCollection,9 ResourceCollection,
11 ResourcePriorities,10 ResourcePriorities,
48 match self {47 match self {
49 Self::Metadata => key!("metadata"),48 Self::Metadata => key!("metadata"),
50 Self::CollectionType => key!("collection-type"),49 Self::CollectionType => key!("collection-type"),
51 Self::Recipient => key!("recipient"),
52 Self::Royalty => key!("royalty"),50 Self::RoyaltyInfo => key!("royalty-info"),
53 Self::Equipped => key!("equipped"),51 Self::Equipped => key!("equipped"),
54 Self::ResourceCollection => key!("resource-collection"),52 Self::ResourceCollection => key!("resource-collection"),
55 Self::ResourcePriorities => key!("resource-priorities"),53 Self::ResourcePriorities => key!("resource-priorities"),
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
188 };188 };
189189
190 let keys = [190 let keys = [
191 RmrkProperty::Royalty,191 RmrkProperty::RoyaltyInfo,
192 RmrkProperty::Metadata,192 RmrkProperty::Metadata,
193 RmrkProperty::Equipped,193 RmrkProperty::Equipped,
194 RmrkProperty::Pending,
195 // ?? "rmrk:recipient", "rmrk:nft-type", "rmrk:resource-collection", "rmrk:resource-priorities"194 // ?? "rmrk:recipient", "rmrk:nft-type", "rmrk:resource-collection", "rmrk:resource-priorities"
196 ];195 ];
197196
315 let collection_id = CollectionId(collection_id);314 let collection_id = CollectionId(collection_id);
316 let nft_id = TokenId(nft_id);315 let nft_id = TokenId(nft_id);
317316
318 let keys = [317 // let keys = [
319 RmrkProperty::Royalty,318 // RmrkProperty::Royalty,
320 RmrkProperty::Metadata,319 // RmrkProperty::Metadata,
321 RmrkProperty::Equipped,320 // RmrkProperty::Equipped,
322 RmrkProperty::Pending,321 // RmrkProperty::Pending,
323 // ?? "rmrk:recipient", "rmrk:nft-type", "rmrk:resource-collection", "rmrk:resource-priorities"322 // // ?? "rmrk:recipient", "rmrk:nft-type", "rmrk:resource-collection", "rmrk:resource-priorities"
324 ];323 // ];
325324
326 /*let resources = keys.into_iter().map(325 /*let resources = keys.into_iter().map(
327 |key| BoundedVec::try_from(326 |key| BoundedVec::try_from(