git.delta.rocks / unique-network / refs/commits / 7c4183b4cb3a

difftreelog

feat(rmrk-rpc) nft resources and priorities

Fahrrader2022-05-26parent: #5c5d937.patch.diff
in: master

6 files changed

modifiedpallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth
486 }486 }
487 }487 }
488488
489 // should this even be here, might displace it to common/nonfungible -- but they did not need it, only rmrk does
490 pub fn collection_exists(collection_id: CollectionId) -> bool {489 pub fn collection_exists(collection_id: CollectionId) -> bool {
491 <pallet_common::CollectionById<T>>::contains_key(collection_id)490 <CollectionHandle<T>>::try_get(collection_id).is_ok()
492 }491 }
493492
494 pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {493 pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {
modifiedpallets/proxy-rmrk-core/src/misc.rsdiffbeforeafterboth
26 }26 }
27}27}
28
29pub trait RmrkRebind<T, S> {
30 fn rebind(&self) -> BoundedVec<u8, S>;
31}
32
33impl<T, S> RmrkRebind<T, S> for BoundedVec<u8, T> where BoundedVec<u8, S>: TryFrom<Vec<u8>> {
34 fn rebind(&self) -> BoundedVec<u8, S> {
35 BoundedVec::<u8, S>::try_from(
36 self.clone().into_inner()
37 ).unwrap_or_default()
38 }
39}
4028
41#[derive(Encode, Decode, PartialEq, Eq)]29#[derive(Encode, Decode, PartialEq, Eq)]
42pub enum CollectionType {30pub enum CollectionType {
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
49 },49 },
50 NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,50 NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,
51 FixedPart as RmrkFixedPart, SlotPart as RmrkSlotPart, EquippableList as RmrkEquippableList,51 FixedPart as RmrkFixedPart, SlotPart as RmrkSlotPart, EquippableList as RmrkEquippableList,
52 BasicResource as RmrkBasicResource, ComposableResource as RmrkComposableResource, SlotResource as RmrkSlotResource,
52};53};
5354
54mod bounded;55mod bounded;
925 }926 }
926}927}
927928
928pub type RmrkCollectionSymbol = BoundedVec<u8, RmrkCollectionSymbolLimit>;
929pub type RmrkCollectionInfo<AccountId> =929pub type RmrkCollectionInfo<AccountId> =
930 CollectionInfo<RmrkString, RmrkCollectionSymbol, AccountId>;930 CollectionInfo<RmrkString, RmrkCollectionSymbol, AccountId>;
931pub type RmrkInstanceInfo<AccountId> = NftInfo<AccountId, Permill, RmrkString>;931pub type RmrkInstanceInfo<AccountId> = NftInfo<AccountId, Permill, RmrkString>;
932pub type RmrkResourceInfo = ResourceInfo<932pub type RmrkResourceInfo = ResourceInfo<
933 BoundedVec<u8, RmrkResourceSymbolLimit>,933 RmrkBoundedResource,
934 RmrkString,934 RmrkString,
935 BoundedVec<RmrkPartId, RmrkPartsLimit>,935 RmrkBoundedParts,
936>;936>;
937pub type RmrkKeyString = BoundedVec<u8, RmrkKeyLimit>;
938pub type RmrkValueString = BoundedVec<u8, RmrkValueLimit>;
939pub type RmrkPropertyInfo = PropertyInfo<RmrkKeyString, RmrkValueString>;937pub type RmrkPropertyInfo = PropertyInfo<RmrkKeyString, RmrkValueString>;
940pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;938pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;
941pub type RmrkPartType =939pub type RmrkPartType =
942 PartType<RmrkString, BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>>;940 PartType<RmrkString, BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>>;
943pub type RmrkThemeProperty = ThemeProperty<RmrkString>;941pub type RmrkThemeProperty = ThemeProperty<RmrkString>;
944pub type RmrkTheme = Theme<RmrkString, Vec<RmrkThemeProperty>>;942pub type RmrkTheme = Theme<RmrkString, Vec<RmrkThemeProperty>>;
943
944pub type RmrkCollectionSymbol = BoundedVec<u8, RmrkCollectionSymbolLimit>;
945pub type RmrkKeyString = BoundedVec<u8, RmrkKeyLimit>;
946pub type RmrkValueString = BoundedVec<u8, RmrkValueLimit>;
947
948type RmrkBoundedResource = BoundedVec<u8, RmrkResourceSymbolLimit>;
949type RmrkBoundedParts = BoundedVec<RmrkPartId, RmrkPartsLimit>;
945950
946pub type RmrkRpcString = Vec<u8>;951pub type RmrkRpcString = Vec<u8>;
947pub type RmrkThemeName = RmrkRpcString;952pub type RmrkThemeName = RmrkRpcString;
modifiedprimitives/data-structs/src/rmrk.rsdiffbeforeafterboth
154 pub value: BoundedValue,154 pub value: BoundedValue,
155}155}
156156
157#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]157#[derive(Encode, Decode, Default, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]
158#[cfg_attr(feature = "std", derive(Serialize))]158#[cfg_attr(feature = "std", derive(Serialize))]
159#[cfg_attr(159#[cfg_attr(
160 feature = "std",160 feature = "std",
275 pub thumb: Option<BoundedString>,275 pub thumb: Option<BoundedString>,
276}276}
277277
278#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]278#[derive(Encode, Decode, Derivative, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]
279#[cfg_attr(feature = "std", derive(Serialize))]279#[cfg_attr(feature = "std", derive(Serialize))]
280#[cfg_attr(280#[cfg_attr(
281 feature = "std",281 feature = "std",
286 "#286 "#
287 )287 )
288)]288)]
289#[derivative(Default(bound=""))]
289pub enum ResourceTypes<BoundedString, BoundedParts> {290pub enum ResourceTypes<BoundedString: Default, BoundedParts> {
291 #[derivative(Default)]
290 Basic(BasicResource<BoundedString>),292 Basic(BasicResource<BoundedString>),
291 Composable(ComposableResource<BoundedString, BoundedParts>),293 Composable(ComposableResource<BoundedString, BoundedParts>),
292 Slot(SlotResource<BoundedString>),294 Slot(SlotResource<BoundedString>),
305 "#307 "#
306 )308 )
307)]309)]
308pub struct ResourceInfo<BoundedResource, BoundedString, BoundedParts> {310pub struct ResourceInfo<BoundedResource, BoundedString: Default, BoundedParts> {
309 /// id is a 5-character string of reasonable uniqueness.311 /// id is a 5-character string of reasonable uniqueness.
310 /// The combination of base ID and resource id should be unique across the entire RMRK312 /// The combination of base ID and resource id should be unique across the entire RMRK
311 /// ecosystem which313 /// ecosystem which
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
146 }146 }
147147
148 fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {148 fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {
149 use frame_support::BoundedVec;
150 use scale_info::prelude::string::String;
151 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, RmrkRebind, RmrkDecode}};149 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, RmrkDecode}};
152150
153 let collection_id = CollectionId(collection_id);151 let collection_id = CollectionId(collection_id);
154 let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Regular) {152 let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Regular) {
155 Ok(c) => c,153 Ok(c) => c,
156 Err(_) => return Ok(None),154 Err(_) => return Ok(None),
157 };155 };
158156
159 let nfts_count = (dispatch_unique_runtime!(collection_id.total_supply()) as Result<u32, DispatchError>)?;157 let nfts_count = dispatch_unique_runtime!(collection_id.total_supply())?;
160 //<Runtime as up_rpc::UniqueApi>::total_supply(collection_id); // todo can't find UniqueApi with disabled default features
161158
162 Ok(Some(RmrkCollectionInfo {159 Ok(Some(RmrkCollectionInfo {
163 issuer: collection.owner.clone(),160 issuer: collection.owner.clone(),
164 metadata: RmrkCore::get_collection_property(collection_id, RmrkProperty::Metadata)?.decode_or_default(),161 metadata: RmrkCore::get_collection_property(collection_id, RmrkProperty::Metadata)?.decode_or_default(),
165 max: collection.limits.token_limit,162 max: collection.limits.token_limit,
166 symbol: collection.token_prefix.rebind(), // change163 symbol: collection.token_prefix.decode_or_default(),
167 nfts_count164 nfts_count
168 }))165 }))
169 }166 }
170167
171 fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {168 fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {
172 use frame_support::BoundedVec;
173 use up_data_structs::mapping::TokenAddressMapping;169 use up_data_structs::mapping::TokenAddressMapping;
174 use pallet_proxy_rmrk_core::{RmrkProperty, misc::RmrkDecode};170 use pallet_proxy_rmrk_core::{RmrkProperty, misc::RmrkDecode};
175171
176 let collection_id = CollectionId(collection_id);172 let collection_id = CollectionId(collection_id);
177 let nft_id = TokenId(nft_by_id);173 let nft_id = TokenId(nft_by_id);
178 if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(None); }174 if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(None); }
179175
180 let owner = match (dispatch_unique_runtime!(collection_id.token_owner(nft_id)) as Result<Option<CrossAccountId>, DispatchError>)? {176 let owner = match dispatch_unique_runtime!(collection_id.token_owner(nft_id))? {
181 Some(owner) => match <Runtime as pallet_common::Config>::CrossTokenAddressMapping::address_to_token(&owner) {177 Some(owner) => match <Runtime as pallet_common::Config>::CrossTokenAddressMapping::address_to_token(&owner) {
182 Some((col, tok)) => RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(col.0, tok.0),178 Some((col, tok)) => RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(col.0, tok.0),
183 None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone())179 None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone())
197 }193 }
198194
199 fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {195 fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {
196 use pallet_proxy_rmrk_core::misc::CollectionType;
197
200 let cross_account_id = CrossAccountId::from_sub(account_id);198 let cross_account_id = CrossAccountId::from_sub(account_id);
201 let collection_id = CollectionId(collection_id);199 let collection_id = CollectionId(collection_id);
202 if !RmrkCore::collection_exists(collection_id) { return Ok(Vec::new()); }200 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }
203201
204 Ok(202 Ok(
205 (dispatch_unique_runtime!(collection_id.account_tokens(cross_account_id)) as Result<Vec<TokenId>, DispatchError>)?203 dispatch_unique_runtime!(collection_id.account_tokens(cross_account_id))?
206 //<Runtime as up_rpc::UniqueApi<Block, CrossAccountId, AccountId>>::account_tokens(collection_id, cross_account_id)?
207 .into_iter()204 .into_iter()
208 .map(|token| token.0)205 .map(|token| token.0)
209 .collect::<Vec<_>>()206 .collect()
210 )207 )
211 }208 }
212209
277273
278 fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {274 fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
279 use frame_support::BoundedVec;275 use frame_support::BoundedVec;
280 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};276 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, RmrkDecode}};
281277
282 let collection_id = CollectionId(collection_id);278 let collection_id = CollectionId(collection_id);
283 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Resource).is_err() { return Ok(Vec::new()); }279 if !RmrkCore::collection_exists(collection_id) { return Ok(Vec::new()); } // todo make sure the collection type doesn't matter
284280
285 let nft_id = TokenId(nft_id);281 let nft_id = TokenId(nft_id);
286 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Resource).is_err() { return Ok(Vec::new()); }282 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Resource).is_err() { return Ok(Vec::new()); }
287283
284 let resource_collection_id: CollectionId = RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::ResourceCollection)
285 .unwrap()
286 .decode_or_default();
288 Ok(Vec::new(/*[RmrkResourceInfo {287 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Resource).is_err() { return Ok(Vec::new()); }
289288
290 }]*/))289 let resources = pallet_nonfungible::TokenProperties::<Runtime>::iter_prefix((resource_collection_id,))
290 .filter_map(|(resource_id, properties)| Some(RmrkResourceInfo {
291 id: BoundedVec::default(), // todo ResourceId property
292 pending: RmrkCore::get_nft_property(resource_collection_id, resource_id, RmrkProperty::PendingResourceAccept).unwrap().decode_or_default(),
293 pending_removal: RmrkCore::get_nft_property(resource_collection_id, resource_id, RmrkProperty::PendingResourceRemoval).unwrap().decode_or_default(),
294 resource: RmrkCore::get_nft_property(resource_collection_id, resource_id, RmrkProperty::ResourceType).unwrap().decode_or_default(),/* {
295 RmrkResourceTypes::Basic(resource) => RmrkResourceTypes::Basic(),/*(RmrkBasicResource {
296 src: RmrkCore::get_nft_property_inner(properties, RmrkProperty::Src).unwrap().decode_or_default(),
297 metadata: RmrkCore::get_nft_property_inner(properties, RmrkProperty::Metadata).unwrap().decode_or_default(),
298 license: RmrkCore::get_nft_property_inner(properties, RmrkProperty::License).unwrap().decode_or_default(),
299 thumb: RmrkCore::get_nft_property_inner(properties, RmrkProperty::Thumb).unwrap().decode_or_default(),
300 },*///BasicResource<BoundedString>)
301 _ => todo!(), //RmrkResourceTypes::Composable(ComposableResource<BoundedString, BoundedParts>),
302 //RmrkResourceTypes::Slot(SlotResource<BoundedString>),
303 },*/
304 }))
305 .collect();
306
307 Ok(resources)
291 }308 }
292309
293 fn nft_resource_priorities(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceId>, DispatchError> {310 fn nft_resource_priorities(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceId>, DispatchError> {
311 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, RmrkDecode}};
312
313 let collection_id = CollectionId(collection_id);
294 todo!()314 if !RmrkCore::collection_exists(collection_id) { return Ok(Vec::new()); } // todo ensure the collection type doesn't matter
315
316 let nft_id = TokenId(nft_id);
317 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Resource).is_err() { return Ok(Vec::new()); }
318
319 /*let resource_collection_id: CollectionId = RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::ResourceCollection)
320 .unwrap()
321 .decode_or_default();
322 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Resource).is_err() { return Ok(Vec::new()); }
323
324 let resources = pallet_nonfungible::TokenProperties::<Runtime>::iter_prefix((resource_collection_id,))
325 .filter_map(|(resource_id, properties)| Some((
326 resource_id, // ResourceId property
327 RmrkCore::get_nft_property(resource_collection_id, resource_id, RmrkProperty::Priority).unwrap().decode_or_default(),
328 )))
329 .collect()
330 .sort_by_key(|(_, index)| *index)
331 .into_iter().map(|(resource_id, _)| resource_id)*/
332 let priorities = RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::ResourcePriorities)?.decode_or_default();
333
334 Ok(priorities)
295 }335 }
296336
297 fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {337 fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
298 use frame_support::BoundedVec;
299 use scale_info::prelude::string::String;
300 use pallet_proxy_rmrk_core::{338 use pallet_proxy_rmrk_core::{
301 RmrkProperty, misc::{CollectionType, RmrkRebind, RmrkDecode},339 RmrkProperty, misc::{CollectionType, RmrkDecode},
302 };340 };
303341
304 let collection_id = CollectionId(base_id);342 let collection_id = CollectionId(base_id);
310 Ok(Some(RmrkBaseInfo {348 Ok(Some(RmrkBaseInfo {
311 issuer: collection.owner.clone(),349 issuer: collection.owner.clone(),
312 base_type: RmrkCore::get_collection_property(collection_id, RmrkProperty::BaseType)?.decode_or_default(),350 base_type: RmrkCore::get_collection_property(collection_id, RmrkProperty::BaseType)?.decode_or_default(),
313 symbol: collection.token_prefix.rebind(),351 symbol: collection.token_prefix.decode_or_default(),
314 }))352 }))
315 }353 }
316354
317 fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {355 fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
318 use frame_support::BoundedVec;
319 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, RmrkDecode}};356 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, RmrkDecode}};
320357
321 let collection_id = CollectionId(base_id);358 let collection_id = CollectionId(base_id);
322 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() { return Ok(Vec::new()); }359 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() { return Ok(Vec::new()); }
323360
324 let parts = (dispatch_unique_runtime!(collection_id.collection_tokens()))?361 let parts = dispatch_unique_runtime!(collection_id.collection_tokens())?
325 .into_iter()362 .into_iter()
326 .filter_map(|token_id| {363 .filter_map(|token_id| {
327 let nft_type = RmrkCore::get_nft_type(collection_id, token_id).ok()?;364 let nft_type = RmrkCore::get_nft_type(collection_id, token_id).ok()?;
347 }384 }
348385
349 fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {386 fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
350 use frame_support::BoundedVec;
351 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, RmrkDecode}};387 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, RmrkDecode}};
352388
353 let collection_id = CollectionId(base_id);389 let collection_id = CollectionId(base_id);
354 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() {390 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() {
355 return Ok(Vec::new());391 return Ok(Vec::new());
356 }392 }
357393
358 let theme_names = (dispatch_unique_runtime!(collection_id.collection_tokens()))?394 let theme_names = dispatch_unique_runtime!(collection_id.collection_tokens())?
359 .iter()395 .iter()
360 .filter_map(|token_id| {396 .filter_map(|token_id| {
361 let nft_type = RmrkCore::get_nft_type(collection_id, *token_id).unwrap();397 let nft_type = RmrkCore::get_nft_type(collection_id, *token_id).unwrap();
373 }409 }
374410
375 fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {411 fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {
376 use frame_support::BoundedVec;
377 use pallet_proxy_rmrk_core::{412 use pallet_proxy_rmrk_core::{
378 RmrkProperty,413 RmrkProperty,
379 misc::{CollectionType, NftType, RmrkDecode}414 misc::{CollectionType, NftType, RmrkDecode}
384 return Ok(None);419 return Ok(None);
385 }420 }
386421
387 let theme_info = (dispatch_unique_runtime!(collection_id.collection_tokens()))?422 let theme_info = dispatch_unique_runtime!(collection_id.collection_tokens())?
388 .into_iter()423 .into_iter()
389 .find_map(|token_id| {424 .find_map(|token_id| {
390 RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Theme).ok()?;425 RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Theme).ok()?;
modifiedtests/src/nesting/properties.test.tsdiffbeforeafterboth
711 });711 });
712 });712 });
713713
714 it('Forbids changing/deleting properties of a token if the property is permanent (constant)', async () => {714 it('Forbids changing/deleting properties of a token if the property is permanent (immutable)', async () => {
715 await usingApi(async api => {715 await usingApi(async api => {
716 let i = -1;716 let i = -1;
717 for (const permission of constitution) {717 for (const permission of constitution) {