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

difftreelog

refactor rmrk proxy, add add_theme rmrk proxy

Daniel Shiposha2022-05-25parent: #4186437.patch.diff
in: master

8 files changed

modifiedclient/rpc/src/lib.rsdiffbeforeafterboth
30// RMRK30// RMRK
31use rmrk_rpc::RmrkApi as RmrkRuntimeApi;31use rmrk_rpc::RmrkApi as RmrkRuntimeApi;
32use up_data_structs::{32use up_data_structs::{
33 RmrkCollectionId, RmrkNftId, RmrkBaseId, RmrkNftChild, RmrkThemeName, RmrkPropertyKey,33 RmrkCollectionId, RmrkNftId, RmrkBaseId, RmrkNftChild, RmrkThemeName,
34 RmrkResourceId,34 RmrkResourceId,
35};35};
3636
248 fn collection_properties(248 fn collection_properties(
249 &self,249 &self,
250 collection_id: RmrkCollectionId,250 collection_id: RmrkCollectionId,
251 filter_keys: Option<Vec<RmrkPropertyKey>>, //String251 filter_keys: Option<Vec<String>>,
252 at: Option<BlockHash>,252 at: Option<BlockHash>,
253 ) -> Result<Vec<PropertyInfo>>;253 ) -> Result<Vec<PropertyInfo>>;
254254
258 &self,258 &self,
259 collection_id: RmrkCollectionId,259 collection_id: RmrkCollectionId,
260 nft_id: RmrkNftId,260 nft_id: RmrkNftId,
261 filter_keys: Option<Vec<RmrkPropertyKey>>,261 filter_keys: Option<Vec<String>>,
262 at: Option<BlockHash>,262 at: Option<BlockHash>,
263 ) -> Result<Vec<PropertyInfo>>;263 ) -> Result<Vec<PropertyInfo>>;
264264
299 fn theme(299 fn theme(
300 &self,300 &self,
301 base_id: RmrkBaseId,301 base_id: RmrkBaseId,
302 theme_name: RmrkThemeName, // String302 theme_name: String,
303 filter_keys: Option<Vec<RmrkPropertyKey>>,303 filter_keys: Option<Vec<String>>,
304 at: Option<BlockHash>,304 at: Option<BlockHash>,
305 ) -> Result<Option<Theme>>;305 ) -> Result<Option<Theme>>;
306 }306 }
523 pass_method!(account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Vec<RmrkNftId>, rmrk_api);523 pass_method!(account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Vec<RmrkNftId>, rmrk_api);
524 pass_method!(nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkNftChild>, rmrk_api);524 pass_method!(nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkNftChild>, rmrk_api);
525 pass_method!(525 pass_method!(
526 collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Vec<PropertyInfo>,526 collection_properties(
527 collection_id: RmrkCollectionId,
528
529 #[map(|keys| string_keys_to_bytes_keys(keys))]
530 filter_keys: Option<Vec<String>>
531 ) -> Vec<PropertyInfo>,
527 rmrk_api532 rmrk_api
528 );533 );
529 pass_method!(534 pass_method!(
530 nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Vec<PropertyInfo>,535 nft_properties(
536 collection_id: RmrkCollectionId,
537 nft_id: RmrkNftId,
538
539 #[map(|keys| string_keys_to_bytes_keys(keys))]
540 filter_keys: Option<Vec<String>>
541 ) -> Vec<PropertyInfo>,
531 rmrk_api542 rmrk_api
532 );543 );
535 pass_method!(base(base_id: RmrkBaseId) -> Option<BaseInfo>, rmrk_api);546 pass_method!(base(base_id: RmrkBaseId) -> Option<BaseInfo>, rmrk_api);
536 pass_method!(base_parts(base_id: RmrkBaseId) -> Vec<PartType>, rmrk_api);547 pass_method!(base_parts(base_id: RmrkBaseId) -> Vec<PartType>, rmrk_api);
537 pass_method!(theme_names(base_id: RmrkBaseId) -> Vec<RmrkThemeName>, rmrk_api);548 pass_method!(theme_names(base_id: RmrkBaseId) -> Vec<RmrkThemeName>, rmrk_api);
538 pass_method!(theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Option<Theme>, rmrk_api);549 pass_method!(
550 theme(
551 base_id: RmrkBaseId,
552
553 #[map(|n| n.into_bytes())]
554 theme_name: String,
555
556 #[map(|keys| string_keys_to_bytes_keys(keys))]
557 filter_keys: Option<Vec<String>>
558 ) -> Option<Theme>, rmrk_api);
539}559}
540560
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
795 }795 }
796796
797 pub fn set_scoped_collection_property(797 pub fn set_scoped_collection_property(
798 collection: &CollectionHandle<T>,798 collection_id: CollectionId,
799 scope: PropertyScope,799 scope: PropertyScope,
800 property: Property,800 property: Property,
801 ) -> DispatchResult {801 ) -> DispatchResult {
802 CollectionProperties::<T>::try_mutate(collection.id, |properties| {802 CollectionProperties::<T>::try_mutate(collection_id, |properties| {
803 properties.try_scoped_set(scope, property.key, property.value)803 properties.try_scoped_set(scope, property.key, property.value)
804 })804 })
805 .map_err(<Error<T>>::from)?;805 .map_err(<Error<T>>::from)?;
806806
807 Ok(())807 Ok(())
808 }808 }
809809
810 #[transactional]
811 pub fn set_scoped_collection_properties(810 pub fn set_scoped_collection_properties(
812 collection: &CollectionHandle<T>,811 collection_id: CollectionId,
813 scope: PropertyScope,812 scope: PropertyScope,
814 properties: impl Iterator<Item = Property>,813 properties: impl Iterator<Item = Property>,
815 ) -> DispatchResult {814 ) -> DispatchResult {
816 CollectionProperties::<T>::try_mutate(collection.id, |stored_properties| {815 CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {
817 stored_properties.try_scoped_set_from_iter(scope, properties)816 stored_properties.try_scoped_set_from_iter(scope, properties)
818 })817 })
819 .map_err(<Error<T>>::from)?;818 .map_err(<Error<T>>::from)?;
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
195 }195 }
196196
197 pub fn set_scoped_token_property(197 pub fn set_scoped_token_property(
198 collection: &CollectionHandle<T>,198 collection_id: CollectionId,
199 token_id: TokenId,199 token_id: TokenId,
200 scope: PropertyScope,200 scope: PropertyScope,
201 property: Property,201 property: Property,
202 ) -> DispatchResult {202 ) -> DispatchResult {
203 TokenProperties::<T>::try_mutate((collection.id, token_id), |properties| {203 TokenProperties::<T>::try_mutate((collection_id, token_id), |properties| {
204 properties.try_scoped_set(scope, property.key, property.value)204 properties.try_scoped_set(scope, property.key, property.value)
205 })205 })
206 .map_err(<CommonError<T>>::from)?;206 .map_err(<CommonError<T>>::from)?;
209 }209 }
210210
211 pub fn set_scoped_token_properties(211 pub fn set_scoped_token_properties(
212 collection: &CollectionHandle<T>,212 collection_id: CollectionId,
213 token_id: TokenId,213 token_id: TokenId,
214 scope: PropertyScope,214 scope: PropertyScope,
215 properties: impl Iterator<Item=Property>,215 properties: impl Iterator<Item=Property>,
216 ) -> DispatchResult {216 ) -> DispatchResult {
217 TokenProperties::<T>::try_mutate((collection.id, token_id), |stored_properties| {217 TokenProperties::<T>::try_mutate((collection_id, token_id), |stored_properties| {
218 stored_properties.try_scoped_set_from_iter(scope, properties)218 stored_properties.try_scoped_set_from_iter(scope, properties)
219 })219 })
220 .map_err(<CommonError<T>>::from)?;220 .map_err(<CommonError<T>>::from)?;
221221
222 Ok(())222 Ok(())
223 }223 }
224224
225 pub fn current_token_id(collection: &CollectionHandle<T>) -> TokenId {225 pub fn current_token_id(collection_id: CollectionId) -> TokenId {
226 TokenId(<TokensMinted<T>>::get(collection.id))226 TokenId(<TokensMinted<T>>::get(collection_id))
227 }227 }
228}228}
229229
modifiedpallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth
33use misc::*;33use misc::*;
34pub use property::*;34pub use property::*;
35
36use RmrkProperty::*;
3537
36#[frame_support::pallet]38#[frame_support::pallet]
37pub mod pallet {39pub mod pallet {
136138
137 let collection_id = collection_id_res?;139 let collection_id = collection_id_res?;
138
139 let collection = Self::get_nft_collection(collection_id)?.into_inner();
140140
141 <PalletCommon<T>>::set_scoped_collection_properties(141 <PalletCommon<T>>::set_scoped_collection_properties(
142 &collection,142 collection_id,
143 PropertyScope::Rmrk,143 PropertyScope::Rmrk,
144 [144 [
145 rmrk_property!(Config=T, Metadata: metadata)?,145 Self::rmrk_property(Metadata, &metadata)?,
146 rmrk_property!(Config=T, CollectionType: CollectionType::Regular)?,146 Self::rmrk_property(CollectionType, &misc::CollectionType::Regular)?,
147 ].into_iter()147 ].into_iter()
148 )?;148 )?;
149149
168168
169 let unique_collection_id = collection_id.into();169 let unique_collection_id = collection_id.into();
170170
171 let collection = Self::get_typed_nft_collection(unique_collection_id, CollectionType::Regular)?;171 let collection = Self::get_typed_nft_collection(unique_collection_id, misc::CollectionType::Regular)?;
172172
173 ensure!(collection.total_supply() == 0, <Error<T>>::CollectionNotEmpty);173 ensure!(collection.total_supply() == 0, <Error<T>>::CollectionNotEmpty);
174174
193193
194 Self::change_collection_owner(194 Self::change_collection_owner(
195 collection_id.into(),195 collection_id.into(),
196 CollectionType::Regular,196 misc::CollectionType::Regular,
197 sender.clone(),197 sender.clone(),
198 new_issuer.clone()198 new_issuer.clone()
199 )?;199 )?;
218218
219 let collection = Self::get_typed_nft_collection(219 let collection = Self::get_typed_nft_collection(
220 collection_id.into(),220 collection_id.into(),
221 CollectionType::Regular221 misc::CollectionType::Regular
222 )?;222 )?;
223223
224 Self::check_collection_owner(&collection, &cross_sender)?;224 Self::check_collection_owner(&collection, &cross_sender)?;
253 amount253 amount
254 });254 });
255
256 let collection = Self::get_typed_nft_collection(
257 collection_id.into(),
258 misc::CollectionType::Regular,
259 )?;
255260
256 let nft_id = Self::create_nft(261 let nft_id = Self::create_nft(
257 &sender,262 &sender,
258 &cross_owner,263 &cross_owner,
259 collection_id.into(),
260 CollectionType::Regular,264 &collection,
261 NftType::Regular,265 NftType::Regular,
262 [266 [
263 rmrk_property!(Config=T, RoyaltyInfo: royalty_info)?,267 Self::rmrk_property(RoyaltyInfo, &royalty_info)?,
264 rmrk_property!(Config=T, Metadata: metadata)?,268 Self::rmrk_property(Metadata, &metadata)?,
265 rmrk_property!(Config=T, Equipped: false)?,269 Self::rmrk_property(Equipped, &false)?,
266 rmrk_property!(Config=T, ResourceCollection: None::<CollectionId>)?,270 Self::rmrk_property(ResourceCollection, &None::<CollectionId>)?,
267 rmrk_property!(Config=T, ResourcePriorities: <Vec<u8>>::new())?,271 Self::rmrk_property(ResourcePriorities, &<Vec<u8>>::new())?,
268 ].into_iter()272 ].into_iter()
269 )?;273 ).map_err(|err| match err {
274 DispatchError::Arithmetic(_) => <Error<T>>::NoAvailableNftId.into(),
275 err => Self::map_common_err_to_proxy(err)
276 })?;
270277
271 Self::deposit_event(Event::NftMinted {278 Self::deposit_event(Event::NftMinted {
272 owner,279 owner,
290 Self::destroy_nft(297 Self::destroy_nft(
291 cross_sender,298 cross_sender,
292 collection_id.into(),299 collection_id.into(),
293 CollectionType::Regular,300 misc::CollectionType::Regular,
294 nft_id.into()301 nft_id.into()
295 )?;302 )?;
296303
302}309}
303310
304impl<T: Config> Pallet<T> {311impl<T: Config> Pallet<T> {
312 pub fn rmrk_property_key(rmrk_key: RmrkProperty) -> Result<PropertyKey, DispatchError> {
313 let key = rmrk_key.to_key::<T>()?;
314
315 let scoped_key = PropertyScope::Rmrk.apply(key)
316 .map_err(|_| <Error<T>>::RmrkPropertyKeyIsTooLong)?;
317
318 Ok(scoped_key)
319 }
320
321 pub fn rmrk_property<E: Encode>(rmrk_key: RmrkProperty, value: &E) -> Result<Property, DispatchError> {
322 let key = rmrk_key.to_key::<T>()?;
323
324 let value = value.encode()
325 .try_into()
326 .map_err(|_| <Error<T>>::RmrkPropertyValueIsTooLong)?;
327
328 let property = Property {
329 key,
330 value,
331 };
332
333 Ok(property)
334 }
335
305 pub fn create_nft(336 pub fn create_nft(
306 sender: &T::CrossAccountId,337 sender: &T::CrossAccountId,
307 owner: &T::CrossAccountId,338 owner: &T::CrossAccountId,
308 collection_id: CollectionId,339 collection: &NonfungibleHandle<T>,
309 collection_type: CollectionType,
310 nft_type: NftType,340 nft_type: NftType,
311 properties: impl Iterator<Item=Property>341 properties: impl Iterator<Item=Property>
312 ) -> Result<TokenId, DispatchError> {342 ) -> Result<TokenId, DispatchError> {
313 let collection = Self::get_typed_nft_collection(
314 collection_id,
315 collection_type
316 )?;
317
318 let data = CreateNftExData {343 let data = CreateNftExData {
319 const_data: nft_type.encode()344 const_data: nft_type.encode()
326 let budget = budget::Value::new(2);351 let budget = budget::Value::new(2);
327352
328 <PalletNft<T>>::create_item(353 <PalletNft<T>>::create_item(
329 &collection,354 collection,
330 sender,355 sender,
331 data,356 data,
332 &budget,357 &budget,
333 ).map_err(Self::map_common_err_to_proxy)?;358 )?;
334359
335 let nft_id = <PalletNft<T>>::current_token_id(&collection);360 let nft_id = <PalletNft<T>>::current_token_id(collection.id);
336361
337 <PalletNft<T>>::set_scoped_token_properties(362 <PalletNft<T>>::set_scoped_token_properties(
338 &collection,363 collection.id,
339 nft_id,364 nft_id,
340 PropertyScope::Rmrk,365 PropertyScope::Rmrk,
341 properties366 properties
347 fn destroy_nft(372 fn destroy_nft(
348 sender: T::CrossAccountId,373 sender: T::CrossAccountId,
349 collection_id: CollectionId,374 collection_id: CollectionId,
350 collection_type: CollectionType,375 collection_type: misc::CollectionType,
351 token_id: TokenId376 token_id: TokenId
352 ) -> DispatchResult {377 ) -> DispatchResult {
353 let collection = Self::get_typed_nft_collection(378 let collection = Self::get_typed_nft_collection(
363388
364 fn change_collection_owner(389 fn change_collection_owner(
365 collection_id: CollectionId,390 collection_id: CollectionId,
366 collection_type: CollectionType,391 collection_type: misc::CollectionType,
367 sender: T::AccountId,392 sender: T::AccountId,
368 new_owner: T::AccountId,393 new_owner: T::AccountId,
369 ) -> DispatchResult {394 ) -> DispatchResult {
391 pub fn get_nft_collection(collection_id: CollectionId) -> Result<NonfungibleHandle<T>, DispatchError> {416 pub fn get_nft_collection(collection_id: CollectionId) -> Result<NonfungibleHandle<T>, DispatchError> {
392 let collection = <CollectionHandle<T>>::try_get(collection_id)417 let collection = <CollectionHandle<T>>::try_get(collection_id)
393 .map_err(|_| <Error<T>>::CollectionUnknown)?418 .map_err(|_| <Error<T>>::CollectionUnknown)?;
394 .into_nft_collection()?;419
395420 match collection.mode {
396 Ok(collection)421 CollectionMode::NFT => Ok(NonfungibleHandle::cast(collection)),
422 _ => Err(<Error<T>>::CollectionUnknown.into())
423 }
397 }424 }
398425
399 // should this even be here, might displace it to common/nonfungible -- but they did not need it, only rmrk does426 // should this even be here, might displace it to common/nonfungible -- but they did not need it, only rmrk does
407434
408 pub fn get_collection_property(collection_id: CollectionId, key: RmrkProperty) -> Result<PropertyValue, DispatchError> {435 pub fn get_collection_property(collection_id: CollectionId, key: RmrkProperty) -> Result<PropertyValue, DispatchError> {
409 let collection_property = <PalletCommon<T>>::collection_properties(collection_id)436 let collection_property = <PalletCommon<T>>::collection_properties(collection_id)
410 .get(&rmrk_property!(Config=T, key)?)437 .get(&Self::rmrk_property_key(key)?)
411 .ok_or(<Error<T>>::CollectionUnknown)?438 .ok_or(<Error<T>>::CollectionUnknown)?
412 .clone();439 .clone();
413440
414 Ok(collection_property)441 Ok(collection_property)
415 }442 }
416443
417 pub fn get_collection_type(collection_id: CollectionId) -> Result<CollectionType, DispatchError> {444 pub fn get_collection_type(collection_id: CollectionId) -> Result<misc::CollectionType, DispatchError> {
418 let value = Self::get_collection_property(collection_id, RmrkProperty::CollectionType)?;445 let value = Self::get_collection_property(collection_id, CollectionType)?;
446
419 let collection_type: CollectionType = (&value)447 let mut value = value.as_slice();
420 .try_into()448
449 misc::CollectionType::decode(&mut value)
421 .map_err(<Error<T>>::from)?;450 .map_err(|_| <Error<T>>::CorruptedCollectionType.into())
422
423 Ok(collection_type)
424 }451 }
425452
426 pub fn ensure_collection_type(collection_id: CollectionId, collection_type: CollectionType) -> DispatchResult {453 pub fn ensure_collection_type(collection_id: CollectionId, collection_type: misc::CollectionType) -> DispatchResult {
427 let actual_type = Self::get_collection_type(collection_id)?;454 let actual_type = Self::get_collection_type(collection_id)?;
428 ensure!(actual_type == collection_type, <CommonError<T>>::NoPermission);455 ensure!(actual_type == collection_type, <CommonError<T>>::NoPermission);
429456
432459
433 pub fn get_nft_property(collection_id: CollectionId, nft_id: TokenId, key: RmrkProperty) -> Result<PropertyValue, DispatchError> {460 pub fn get_nft_property(collection_id: CollectionId, nft_id: TokenId, key: RmrkProperty) -> Result<PropertyValue, DispatchError> {
434 let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))461 let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))
435 .get(&rmrk_property!(Config=T, key)?)462 .get(&Self::rmrk_property_key(key)?)
436 .ok_or(<Error<T>>::NoAvailableNftId)?463 .ok_or(<Error<T>>::NoAvailableNftId)?
437 .clone();464 .clone();
438465
439 Ok(nft_property)466 Ok(nft_property)
440 }467 }
441468
442 pub fn get_nft_type(collection_id: CollectionId, token_id: TokenId) -> Result<NftType, DispatchError> {469 pub fn get_nft_type(collection_id: CollectionId, token_id: TokenId) -> Result<NftType, DispatchError> {
470 let token_data = <TokenData<T>>::get((collection_id, token_id))
471 .ok_or(<Error<T>>::NoAvailableNftId)?;
472
473 let mut const_data = token_data.const_data.as_slice();
474
443 <TokenData<T>>::get((collection_id, token_id))475 NftType::decode(&mut const_data).map_err(|_| <Error<T>>::NoAvailableNftId.into())
444 .unwrap()
445 .rmrk_nft_type()
446 .ok_or_else(|| <Error<T>>::NoAvailableNftId.into())
447 }476 }
448477
449 pub fn ensure_nft_type(collection_id: CollectionId, token_id: TokenId, nft_type: NftType) -> DispatchResult {478 pub fn ensure_nft_type(collection_id: CollectionId, token_id: TokenId, nft_type: NftType) -> DispatchResult {
466 let value = Self::get_nft_property(495 let value = Self::get_nft_property(
467 collection_id,496 collection_id,
468 token_id,497 token_id,
469 RmrkProperty::ThemeProperty(&key)498 ThemeProperty(&key)
470 ).ok()?.decode_or_default();499 ).ok()?.decode_or_default();
471500
472 let property = RmrkThemeProperty {501 let property = RmrkThemeProperty {
491 collection_id: CollectionId,520 collection_id: CollectionId,
492 token_id: TokenId521 token_id: TokenId
493 ) -> Result<impl Iterator<Item=RmrkThemeProperty>, DispatchError> {522 ) -> Result<impl Iterator<Item=RmrkThemeProperty>, DispatchError> {
494 let key_prefix = rmrk_property!(Config=T, key: ThemeProperty(&RmrkString::default()))?;523 let key_prefix = Self::rmrk_property_key(ThemeProperty(&RmrkString::default()))?;
495524
496 let properties = <PalletNft<T>>::token_properties((collection_id, token_id))525 let properties = <PalletNft<T>>::token_properties((collection_id, token_id))
497 .into_iter()526 .into_iter()
514543
515 pub fn get_typed_nft_collection(544 pub fn get_typed_nft_collection(
516 collection_id: CollectionId,545 collection_id: CollectionId,
517 collection_type: CollectionType546 collection_type: misc::CollectionType
518 ) -> Result<NonfungibleHandle<T>, DispatchError> {547 ) -> Result<NonfungibleHandle<T>, DispatchError> {
519 Self::ensure_collection_type(collection_id, collection_type)?;548 Self::ensure_collection_type(collection_id, collection_type)?;
520549
modifiedpallets/proxy-rmrk-core/src/misc.rsdiffbeforeafterboth
1use super::*;1use super::*;
2use codec::{Encode, Decode};2use codec::{Encode, Decode};
3use pallet_nonfungible::{NonfungibleHandle, ItemData};
4
5macro_rules! impl_rmrk_value {
6 ($enum_name:path, decode_error: $error:ident) => {
7 impl TryFrom<&PropertyValue> for $enum_name {
8 type Error = MiscError;
9
10 fn try_from(value: &PropertyValue) -> Result<Self, Self::Error> {
11 let mut value = value.as_slice();
12
13 <$enum_name>::decode(&mut value)
14 .map_err(|_| MiscError::$error)
15 }
16 }
17
18 };
19}
203
21#[macro_export]4#[macro_export]
22macro_rules! map_common_err_to_proxy {5macro_rules! map_common_err_to_proxy {
31 };14 };
32}15}
33
34pub enum MiscError {
35 RmrkPropertyValueIsTooLong,
36 CorruptedCollectionType,
37}
38
39impl<T: Config> From<MiscError> for Error<T> {
40 fn from(error: MiscError) -> Self {
41 match error {
42 MiscError::RmrkPropertyValueIsTooLong => Self::RmrkPropertyValueIsTooLong,
43 MiscError::CorruptedCollectionType => Self::CorruptedCollectionType,
44 }
45 }
46}
47
48pub trait IntoNftCollection<T: Config> {
49 fn into_nft_collection(self) -> Result<NonfungibleHandle<T>, Error<T>>;
50}
51
52impl<T: Config> IntoNftCollection<T> for CollectionHandle<T> {
53 fn into_nft_collection(self) -> Result<NonfungibleHandle<T>, Error<T>> {
54 match self.mode {
55 CollectionMode::NFT => Ok(NonfungibleHandle::cast(self)),
56 _ => Err(<Error<T>>::CollectionUnknown)
57 }
58 }
59}
60
61pub trait IntoPropertyValue {
62 fn into_property_value(self) -> Result<PropertyValue, MiscError>;
63}
64
65impl<T: Encode> IntoPropertyValue for T {
66 fn into_property_value(self) -> Result<PropertyValue, MiscError> {
67 self.encode()
68 .try_into()
69 .map_err(|_| MiscError::RmrkPropertyValueIsTooLong)
70 }
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}
8416
85pub trait RmrkDecode<T: Decode + Default, S> {17pub trait RmrkDecode<T: Decode + Default, S> {
86 fn decode_or_default(&self) -> T;18 fn decode_or_default(&self) -> T;
122 Theme54 Theme
123}55}
124
125impl_rmrk_value!(CollectionType, decode_error: CorruptedCollectionType);
12656
modifiedpallets/proxy-rmrk-core/src/property.rsdiffbeforeafterboth
72 }72 }
73}73}
74
75#[macro_export]
76macro_rules! rmrk_property {
77 (Config=$cfg:ty, key: $key:ident $(($key_ext:expr))?) => {
78 rmrk_property!(Config=$cfg, $crate::RmrkProperty::$key $(($key_ext))?)
79 };
80
81 (Config=$cfg:ty, $key:ident $(($key_ext:expr))?: $value:expr) => {{
82 let key = rmrk_property!(@$cfg, $crate::RmrkProperty::$key $(($key_ext))?)?;
83
84 let value = $value.into_property_value()
85 .map_err(<$crate::Error<$cfg>>::from)?;
86
87 Ok::<_, $crate::Error<$cfg>>(Property {
88 key,
89 value,
90 })
91 }};
92
93 (@$cfg:ty, $key_enum:expr) => {
94 $key_enum.to_key::<$cfg>()
95 };
96
97 (Config=$cfg:ty, $key_enum:expr) => {
98 PropertyScope::Rmrk.apply(rmrk_property!(@$cfg, $key_enum)?)
99 .map_err(|_| <$crate::Error<$cfg>>::RmrkPropertyKeyIsTooLong)
100 };
101}
10274
modifiedpallets/proxy-rmrk-equip/src/lib.rsdiffbeforeafterboth
20use frame_system::{pallet_prelude::*, ensure_signed};20use frame_system::{pallet_prelude::*, ensure_signed};
21use sp_runtime::DispatchError;21use sp_runtime::DispatchError;
22use up_data_structs::*;22use up_data_structs::*;
23use pallet_common::{Pallet as PalletCommon, Error as CommonError, CollectionHandle};23use pallet_common::{Pallet as PalletCommon, Error as CommonError};
24use pallet_rmrk_core::{Pallet as PalletCore, rmrk_property, misc::*};24use pallet_rmrk_core::{Pallet as PalletCore, misc::{self, *}, property::RmrkProperty::*};
25use pallet_nonfungible::{Pallet as PalletNft};25use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle};
26use pallet_evm::account::CrossAccountId;26use pallet_evm::account::CrossAccountId;
2727
28pub use pallet::*;28pub use pallet::*;
48 TokenId48 TokenId
49 >;49 >;
50
51 #[pallet::storage]
52 #[pallet::getter(fn base_has_default_theme)]
53 pub type BaseHasDefaultTheme<T: Config> = StorageMap<
54 _,
55 Twox64Concat,
56 CollectionId,
57 bool,
58 ValueQuery
59 >;
5060
51 #[pallet::pallet]61 #[pallet::pallet]
52 #[pallet::generate_store(pub(super) trait Store)]62 #[pallet::generate_store(pub(super) trait Store)]
6373
64 #[pallet::error]74 #[pallet::error]
65 pub enum Error<T> {75 pub enum Error<T> {
76 PermissionError,
66 NoAvailableBaseId,77 NoAvailableBaseId,
78 NoAvailablePartId,
79 BaseDoesntExist,
80 NeedsDefaultThemeFirst,
67 }81 }
6882
69 #[pallet::call]83 #[pallet::call]
95109
96 let collection_id = collection_id_res?;110 let collection_id = collection_id_res?;
97
98 let collection = <PalletCore<T>>::get_nft_collection(collection_id)?.into_inner();
99111
100 <PalletCommon<T>>::set_scoped_collection_properties(112 <PalletCommon<T>>::set_scoped_collection_properties(
101 &collection,113 collection_id,
102 PropertyScope::Rmrk,114 PropertyScope::Rmrk,
103 [115 [
104 rmrk_property!(Config=T, CollectionType: CollectionType::Base)?,116 <PalletCore<T>>::rmrk_property(CollectionType, &misc::CollectionType::Base)?,
105 rmrk_property!(Config=T, BaseType: base_type)?,117 <PalletCore<T>>::rmrk_property(BaseType, &base_type)?,
106 ].into_iter()118 ].into_iter()
107 )?;119 )?;
120
121 let collection = <PalletCore<T>>::get_nft_collection(collection_id)?;
108122
109 for part in parts {123 for part in parts {
110 let part_id = part.id();124 let part_id = part.id();
117 <InernalPartId<T>>::insert(collection_id, part_id, part_token_id);131 <InernalPartId<T>>::insert(collection_id, part_id, part_token_id);
118132
119 <PalletNft<T>>::set_scoped_token_property(133 <PalletNft<T>>::set_scoped_token_property(
120 &collection,134 collection_id,
121 part_token_id,135 part_token_id,
122 PropertyScope::Rmrk,136 PropertyScope::Rmrk,
123 rmrk_property!(Config=T, ExternalPartId: part_id)?137 <PalletCore<T>>::rmrk_property(ExternalPartId, &part_id)?
124 )?;138 )?;
125 }139 }
126140
129 Ok(())143 Ok(())
130 }144 }
145
146 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
147 #[transactional]
148 pub fn theme_add(
149 origin: OriginFor<T>,
150 base_id: RmrkBaseId,
151 theme: RmrkTheme,
152 ) -> DispatchResult {
153 let sender = ensure_signed(origin)?;
154
155 let sender = T::CrossAccountId::from_sub(sender);
156 let owner = &sender;
157
158 let collection_id: CollectionId = base_id.into();
159
160 let collection = <PalletCore<T>>::get_typed_nft_collection(
161 collection_id,
162 misc::CollectionType::Base
163 ).map_err(|_| <Error<T>>::BaseDoesntExist)?;
164
165 if theme.name.as_slice() == b"default" {
166 <BaseHasDefaultTheme<T>>::insert(collection_id, true);
167 } else if !Self::base_has_default_theme(collection_id) {
168 return Err(<Error<T>>::NeedsDefaultThemeFirst.into());
169 }
170
171 let token_id = <PalletCore<T>>::create_nft(
172 &sender,
173 owner,
174 &collection,
175 NftType::Theme,
176 [
177 <PalletCore<T>>::rmrk_property(ThemeName, &theme.name)?,
178 <PalletCore<T>>::rmrk_property(ThemeInherit, &theme.inherit)?
179 ].into_iter()
180 ).map_err(|_| <Error<T>>::PermissionError)?;
181
182 for property in theme.properties {
183 <PalletNft<T>>::set_scoped_token_property(
184 collection_id,
185 token_id,
186 PropertyScope::Rmrk,
187 <PalletCore<T>>::rmrk_property(
188 ThemeProperty(&property.key),
189 &property.value
190 )?
191 )?;
192 }
193
194 Ok(())
195 }
131 }196 }
132}197}
133198
134impl<T: Config> Pallet<T> {199impl<T: Config> Pallet<T> {
135 fn create_part(200 fn create_part(
136 sender: &T::CrossAccountId,201 sender: &T::CrossAccountId,
137 collection: &CollectionHandle<T>,202 collection: &NonfungibleHandle<T>,
138 part: RmrkPartType203 part: RmrkPartType
139 ) -> Result<TokenId, DispatchError> {204 ) -> Result<TokenId, DispatchError> {
140 let owner = sender;205 let owner = sender;
150 let token_id = <PalletCore<T>>::create_nft(215 let token_id = <PalletCore<T>>::create_nft(
151 sender,216 sender,
152 owner,217 owner,
153 collection.id,218 collection,
154 CollectionType::Base,
155 nft_type,219 nft_type,
156 [220 [
157 rmrk_property!(Config=T, Src: src)?,221 <PalletCore<T>>::rmrk_property(Src, &src)?,
158 rmrk_property!(Config=T, ZIndex: z_index)?222 <PalletCore<T>>::rmrk_property(ZIndex, &z_index)?
159 ].into_iter()223 ].into_iter()
160 )?;224 ).map_err(|err| match err {
225 DispatchError::Arithmetic(_) => <Error<T>>::NoAvailablePartId.into(),
226 err => err
227 })?;
161228
162 if let RmrkPartType::SlotPart(part) = part {229 if let RmrkPartType::SlotPart(part) = part {
163 <PalletNft<T>>::set_scoped_token_property(230 <PalletNft<T>>::set_scoped_token_property(
164 collection,231 collection.id,
165 token_id,232 token_id,
166 PropertyScope::Rmrk,233 PropertyScope::Rmrk,
167 rmrk_property!(Config=T, EquippableList: part.equippable)?234 <PalletCore<T>>::rmrk_property(EquippableList, &part.equippable)?
168 )?;235 )?;
169 }236 }
170237
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
347347
348 fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {348 fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
349 use frame_support::BoundedVec;349 use frame_support::BoundedVec;
350 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, RmrkNft, RmrkDecode}};350 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, RmrkDecode}};
351351
352 let collection_id = CollectionId(base_id);352 let collection_id = CollectionId(base_id);
353 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() { return Ok(Vec::new()); }353 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() { return Ok(Vec::new()); }
379379
380 fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {380 fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
381 use frame_support::BoundedVec;381 use frame_support::BoundedVec;
382 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, RmrkNft, RmrkDecode}};382 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, RmrkDecode}};
383383
384 let collection_id = CollectionId(base_id);384 let collection_id = CollectionId(base_id);
385 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() {385 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() {
407 use frame_support::BoundedVec;407 use frame_support::BoundedVec;
408 use pallet_proxy_rmrk_core::{408 use pallet_proxy_rmrk_core::{
409 RmrkProperty,409 RmrkProperty,
410 misc::{CollectionType, NftType, RmrkNft, RmrkDecode}410 misc::{CollectionType, NftType, RmrkDecode}
411 };411 };
412412
413 let collection_id = CollectionId(base_id);413 let collection_id = CollectionId(base_id);