difftreelog
Merge pull request #385 from UniqueNetwork/feature/conditional-rmrk
in: master
feat(rmrk): remove RMRK proxy from unique runtime
10 files changed
node/rpc/Cargo.tomldiffbeforeafterboth63[features]63[features]64default = []64default = []65std = []65std = []66unique-runtime = []6667node/rpc/src/lib.rsdiffbeforeafterboth169 Eth, EthApiServer, EthDevSigner, EthFilter, EthFilterApiServer, EthPubSub,169 Eth, EthApiServer, EthDevSigner, EthFilter, EthFilterApiServer, EthPubSub,170 EthPubSubApiServer, EthSigner, Net, NetApiServer, Web3, Web3ApiServer,170 EthPubSubApiServer, EthSigner, Net, NetApiServer, Web3, Web3ApiServer,171 };171 };172 use uc_rpc::{UniqueApiServer, Unique, RmrkApiServer, Rmrk};172 use uc_rpc::{UniqueApiServer, Unique};173174 #[cfg(not(feature = "unique-runtime"))]175 use uc_rpc::{RmrkApiServer, Rmrk};176173 // use pallet_contracts_rpc::{Contracts, ContractsApi};177 // use pallet_contracts_rpc::{Contracts, ContractsApi};174 use pallet_transaction_payment_rpc::{TransactionPaymentRpc, TransactionPaymentApiServer};178 use pallet_transaction_payment_rpc::{TransactionPaymentRpc, TransactionPaymentApiServer};224228225 io.merge(Unique::new(client.clone()).into_rpc())?;229 io.merge(Unique::new(client.clone()).into_rpc())?;230231 #[cfg(not(feature = "unique-runtime"))]226 io.merge(Rmrk::new(client.clone()).into_rpc())?;232 io.merge(Rmrk::new(client.clone()).into_rpc())?;227233228 if let Some(filter_pool) = filter_pool {234 if let Some(filter_pool) = filter_pool {runtime/common/src/runtime_apis.rsdiffbeforeafterboth144 }144 }145 }145 }146147 impl rmrk_rpc::RmrkApi<148 Block,149 AccountId,150 RmrkCollectionInfo<AccountId>,151 RmrkInstanceInfo<AccountId>,152 RmrkResourceInfo,153 RmrkPropertyInfo,154 RmrkBaseInfo<AccountId>,155 RmrkPartType,156 RmrkTheme157 > for Runtime {158 fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {159 Ok(RmrkCore::last_collection_idx())160 }161162 fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {163 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};164 use pallet_common::CommonCollectionOperations;165166 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) {167 Ok(c) => c,168 Err(_) => return Ok(None),169 };170171 let nfts_count = collection.total_supply();172173 Ok(Some(RmrkCollectionInfo {174 issuer: collection.owner.clone(),175 metadata: RmrkCore::get_collection_property_decoded(collection_id, RmrkProperty::Metadata)?,176 max: collection.limits.token_limit,177 symbol: RmrkCore::rebind(&collection.token_prefix)?,178 nfts_count179 }))180 }181182 fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {183 use up_data_structs::mapping::TokenAddressMapping;184 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};185 use pallet_common::CommonCollectionOperations;186187 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) {188 Ok(c) => c,189 Err(_) => return Ok(None),190 };191192 let nft_id = TokenId(nft_by_id);193 if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(None); }194195 let owner = match collection.token_owner(nft_id) {196 Some(owner) => match <Runtime as pallet_common::Config>::CrossTokenAddressMapping::address_to_token(&owner) {197 Some((col, tok)) => {198 let rmrk_collection = RmrkCore::rmrk_collection_id(col)?;199200 RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0)201 }202 None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone())203 },204 None => return Ok(None)205 };206207 Ok(Some(RmrkInstanceInfo {208 owner: owner,209 royalty: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::RoyaltyInfo)?,210 metadata: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Metadata)?,211 equipped: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Equipped)?,212 pending: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::PendingNftAccept)?,213 }))214 }215216 fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {217 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};218 use pallet_common::CommonCollectionOperations;219220 let cross_account_id = CrossAccountId::from_sub(account_id);221222 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) {223 Ok(c) => c,224 Err(_) => return Ok(Vec::new()),225 };226227 let tokens = collection.account_tokens(cross_account_id)228 .into_iter()229 .filter(|token| {230 let is_pending = RmrkCore::get_nft_property_decoded(231 collection_id,232 *token,233 RmrkProperty::PendingNftAccept234 ).unwrap_or(true);235236 !is_pending237 })238 .map(|token| token.0)239 .collect();240241 Ok(tokens)242 }243244 fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {245 use pallet_proxy_rmrk_core::RmrkProperty;246247 let collection_id = match RmrkCore::unique_collection_id(collection_id) {248 Ok(id) => id,249 Err(_) => return Ok(Vec::new())250 };251 let nft_id = TokenId(nft_id);252 if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(Vec::new()); }253254 Ok(255 pallet_nonfungible::TokenChildren::<Runtime>::iter_prefix((collection_id, nft_id))256 .filter_map(|((child_collection, child_token), _)| {257 let is_pending = RmrkCore::get_nft_property_decoded(258 child_collection,259 child_token,260 RmrkProperty::PendingNftAccept261 ).ok()?;262263 if is_pending {264 return None;265 }266267 let rmrk_child_collection = RmrkCore::rmrk_collection_id(268 child_collection269 ).ok()?;270271 Some(RmrkNftChild {272 collection_id: rmrk_child_collection,273 nft_id: child_token.0,274 })275 }).collect()276 )277 }278279 fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {280 use pallet_proxy_rmrk_core::misc::CollectionType;281282 let collection_id = match RmrkCore::unique_collection_id(collection_id) {283 Ok(id) => id,284 Err(_) => return Ok(Vec::new())285 };286 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() {287 return Ok(Vec::new());288 }289290 let properties = RmrkCore::filter_user_properties(291 collection_id,292 /* token_id = */ None,293 filter_keys,294 |key, value| RmrkPropertyInfo {295 key,296 value297 }298 )?;299300 Ok(properties)301 }302303 fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {304 use pallet_proxy_rmrk_core::misc::NftType;305306 let collection_id = match RmrkCore::unique_collection_id(collection_id) {307 Ok(id) => id,308 Err(_) => return Ok(Vec::new())309 };310 let token_id = TokenId(nft_id);311312 if RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() {313 return Ok(Vec::new());314 }315316 let properties = RmrkCore::filter_user_properties(317 collection_id,318 Some(token_id),319 filter_keys,320 |key, value| RmrkPropertyInfo {321 key,322 value323 }324 )?;325326 Ok(properties)327 }328329 fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {330 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, ResourceType}};331 use pallet_common::CommonCollectionOperations;332333 let collection_id = match RmrkCore::unique_collection_id(collection_id) {334 Ok(id) => id,335 Err(_) => return Ok(Vec::new())336 };337 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }338339 let nft_id = TokenId(nft_id);340 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); }341342 let res_collection_id: Option<CollectionId> = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)?;343344 let res_collection_id = match res_collection_id {345 Some(id) => id,346 None => return Ok(Vec::new())347 };348349 let resource_collection = RmrkCore::get_typed_nft_collection(res_collection_id, CollectionType::Resource)?;350351 let resources = resource_collection352 .collection_tokens()353 .iter()354 .filter_map(|(res_id)| Some(RmrkResourceInfo {355 id: res_id.0,356 pending: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceAccept).ok()?,357 pending_removal: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceRemoval).ok()?,358 resource: match RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::ResourceType).ok()? {359 ResourceType::Basic => RmrkResourceTypes::Basic(RmrkBasicResource {360 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,361 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,362 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,363 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,364 }),365 ResourceType::Composable => RmrkResourceTypes::Composable(RmrkComposableResource {366 parts: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Parts).ok()?,367 base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?,368 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,369 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,370 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,371 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,372 }),373 ResourceType::Slot => RmrkResourceTypes::Slot(RmrkSlotResource {374 base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?,375 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,376 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,377 slot: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Slot).ok()?,378 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,379 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,380 }),381 },382 }))383 .collect();384385 Ok(resources)386 }387388 fn nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Result<Option<u32>, DispatchError> {389 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};390391 let collection_id = match RmrkCore::unique_collection_id(collection_id) {392 Ok(id) => id,393 Err(_) => return Ok(None)394 };395 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(None); }396397 let nft_id = TokenId(nft_id);398 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(None); }399400 let priorities: Vec<_> = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourcePriorities)?;401 Ok(402 priorities.into_iter()403 .enumerate()404 .find(|(_, id)| *id == resource_id)405 .map(|(priority, _): (usize, RmrkResourceId)| priority as u32)406 )407 }408409 fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {410 use pallet_proxy_rmrk_core::{411 RmrkProperty, misc::{CollectionType},412 };413414 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) {415 Ok(c) => c,416 Err(_) => return Ok(None),417 };418419 Ok(Some(RmrkBaseInfo {420 issuer: collection.owner.clone(),421 base_type: RmrkCore::get_collection_property_decoded(collection_id, RmrkProperty::BaseType)?,422 symbol: RmrkCore::rebind(&collection.token_prefix)?,423 }))424 }425426 fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {427 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};428 use pallet_common::CommonCollectionOperations;429430 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) {431 Ok(c) => c,432 Err(_) => return Ok(Vec::new()),433 };434435 let parts = collection.collection_tokens()436 .into_iter()437 .filter_map(|token_id| {438 let nft_type = RmrkCore::get_nft_type(collection_id, token_id).ok()?;439440 match nft_type {441 NftType::FixedPart => Some(RmrkPartType::FixedPart(RmrkFixedPart {442 id: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?,443 src: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::Src).ok()?,444 z: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ZIndex).ok()?,445 })),446 NftType::SlotPart => Some(RmrkPartType::SlotPart(RmrkSlotPart {447 id: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?,448 src: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::Src).ok()?,449 z: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ZIndex).ok()?,450 equippable: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::EquippableList).ok()?,451 })),452 _ => None453 }454 })455 .collect();456457 Ok(parts)458 }459460 fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {461 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};462 use pallet_common::CommonCollectionOperations;463464 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) {465 Ok(c) => c,466 Err(_) => return Ok(Vec::new()),467 };468469 let theme_names = collection.collection_tokens()470 .iter()471 .filter_map(|token_id| {472 let nft_type = RmrkCore::get_nft_type(collection_id, *token_id).ok()?;473474 match nft_type {475 Theme => RmrkCore::get_nft_property_decoded(collection_id, *token_id, RmrkProperty::ThemeName).ok(),476 _ => None477 }478 })479 .collect();480481 Ok(theme_names)482 }483484 fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {485 use pallet_proxy_rmrk_core::{486 RmrkProperty,487 misc::{CollectionType, NftType}488 };489 use pallet_common::CommonCollectionOperations;490491 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) {492 Ok(c) => c,493 Err(_) => return Ok(None),494 };495496 let theme_info = collection.collection_tokens()497 .into_iter()498 .find_map(|token_id| {499 RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Theme).ok()?;500501 let name: RmrkString = RmrkCore::get_nft_property_decoded(502 collection_id, token_id, RmrkProperty::ThemeName503 ).ok()?;504505 if name == theme_name {506 Some((name, token_id))507 } else {508 None509 }510 });511512 let (name, theme_id) = match theme_info {513 Some((name, theme_id)) => (name, theme_id),514 None => return Ok(None)515 };516517 let properties = RmrkCore::filter_user_properties(518 collection_id,519 Some(theme_id),520 filter_keys,521 |key, value| RmrkThemeProperty {522 key,523 value524 }525 )?;526527 let inherit = RmrkCore::get_nft_property_decoded(528 collection_id,529 theme_id,530 RmrkProperty::ThemeInherit531 )?;532533 let theme = RmrkTheme {534 name,535 properties,536 inherit,537 };538539 Ok(Some(theme))540 }541 }542146543 impl sp_api::Core<Block> for Runtime {147 impl sp_api::Core<Block> for Runtime {544 fn version() -> RuntimeVersion {148 fn version() -> RuntimeVersion {runtime/opal/src/lib.rsdiffbeforeafterboth1315 }};1315 }};1316}1316}131713171318impl_common_runtime_apis!();1318impl_common_runtime_apis! {1319 #![custom_apis]13201321 impl rmrk_rpc::RmrkApi<1322 Block,1323 AccountId,1324 RmrkCollectionInfo<AccountId>,1325 RmrkInstanceInfo<AccountId>,1326 RmrkResourceInfo,1327 RmrkPropertyInfo,1328 RmrkBaseInfo<AccountId>,1329 RmrkPartType,1330 RmrkTheme1331 > for Runtime {1332 fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {1333 Ok(RmrkCore::last_collection_idx())1334 }13351336 fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {1337 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};1338 use pallet_common::CommonCollectionOperations;13391340 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) {1341 Ok(c) => c,1342 Err(_) => return Ok(None),1343 };13441345 let nfts_count = collection.total_supply();13461347 Ok(Some(RmrkCollectionInfo {1348 issuer: collection.owner.clone(),1349 metadata: RmrkCore::get_collection_property_decoded(collection_id, RmrkProperty::Metadata)?,1350 max: collection.limits.token_limit,1351 symbol: RmrkCore::rebind(&collection.token_prefix)?,1352 nfts_count1353 }))1354 }13551356 fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {1357 use up_data_structs::mapping::TokenAddressMapping;1358 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};1359 use pallet_common::CommonCollectionOperations;13601361 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) {1362 Ok(c) => c,1363 Err(_) => return Ok(None),1364 };13651366 let nft_id = TokenId(nft_by_id);1367 if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(None); }13681369 let owner = match collection.token_owner(nft_id) {1370 Some(owner) => match <Runtime as pallet_common::Config>::CrossTokenAddressMapping::address_to_token(&owner) {1371 Some((col, tok)) => {1372 let rmrk_collection = RmrkCore::rmrk_collection_id(col)?;13731374 RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0)1375 }1376 None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone())1377 },1378 None => return Ok(None)1379 };13801381 Ok(Some(RmrkInstanceInfo {1382 owner: owner,1383 royalty: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::RoyaltyInfo)?,1384 metadata: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Metadata)?,1385 equipped: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Equipped)?,1386 pending: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::PendingNftAccept)?,1387 }))1388 }13891390 fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {1391 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};1392 use pallet_common::CommonCollectionOperations;13931394 let cross_account_id = CrossAccountId::from_sub(account_id);13951396 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) {1397 Ok(c) => c,1398 Err(_) => return Ok(Vec::new()),1399 };14001401 let tokens = collection.account_tokens(cross_account_id)1402 .into_iter()1403 .filter(|token| {1404 let is_pending = RmrkCore::get_nft_property_decoded(1405 collection_id,1406 *token,1407 RmrkProperty::PendingNftAccept1408 ).unwrap_or(true);14091410 !is_pending1411 })1412 .map(|token| token.0)1413 .collect();14141415 Ok(tokens)1416 }14171418 fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {1419 use pallet_proxy_rmrk_core::RmrkProperty;14201421 let collection_id = match RmrkCore::unique_collection_id(collection_id) {1422 Ok(id) => id,1423 Err(_) => return Ok(Vec::new())1424 };1425 let nft_id = TokenId(nft_id);1426 if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(Vec::new()); }14271428 Ok(1429 pallet_nonfungible::TokenChildren::<Runtime>::iter_prefix((collection_id, nft_id))1430 .filter_map(|((child_collection, child_token), _)| {1431 let is_pending = RmrkCore::get_nft_property_decoded(1432 child_collection,1433 child_token,1434 RmrkProperty::PendingNftAccept1435 ).ok()?;14361437 if is_pending {1438 return None;1439 }14401441 let rmrk_child_collection = RmrkCore::rmrk_collection_id(1442 child_collection1443 ).ok()?;14441445 Some(RmrkNftChild {1446 collection_id: rmrk_child_collection,1447 nft_id: child_token.0,1448 })1449 }).collect()1450 )1451 }14521453 fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {1454 use pallet_proxy_rmrk_core::misc::CollectionType;14551456 let collection_id = match RmrkCore::unique_collection_id(collection_id) {1457 Ok(id) => id,1458 Err(_) => return Ok(Vec::new())1459 };1460 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() {1461 return Ok(Vec::new());1462 }14631464 let properties = RmrkCore::filter_user_properties(1465 collection_id,1466 /* token_id = */ None,1467 filter_keys,1468 |key, value| RmrkPropertyInfo {1469 key,1470 value1471 }1472 )?;14731474 Ok(properties)1475 }14761477 fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {1478 use pallet_proxy_rmrk_core::misc::NftType;14791480 let collection_id = match RmrkCore::unique_collection_id(collection_id) {1481 Ok(id) => id,1482 Err(_) => return Ok(Vec::new())1483 };1484 let token_id = TokenId(nft_id);14851486 if RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() {1487 return Ok(Vec::new());1488 }14891490 let properties = RmrkCore::filter_user_properties(1491 collection_id,1492 Some(token_id),1493 filter_keys,1494 |key, value| RmrkPropertyInfo {1495 key,1496 value1497 }1498 )?;14991500 Ok(properties)1501 }15021503 fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {1504 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, ResourceType}};1505 use pallet_common::CommonCollectionOperations;15061507 let collection_id = match RmrkCore::unique_collection_id(collection_id) {1508 Ok(id) => id,1509 Err(_) => return Ok(Vec::new())1510 };1511 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }15121513 let nft_id = TokenId(nft_id);1514 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); }15151516 let res_collection_id: Option<CollectionId> = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)?;15171518 let res_collection_id = match res_collection_id {1519 Some(id) => id,1520 None => return Ok(Vec::new())1521 };15221523 let resource_collection = RmrkCore::get_typed_nft_collection(res_collection_id, CollectionType::Resource)?;15241525 let resources = resource_collection1526 .collection_tokens()1527 .iter()1528 .filter_map(|res_id| Some(RmrkResourceInfo {1529 id: res_id.0,1530 pending: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceAccept).ok()?,1531 pending_removal: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceRemoval).ok()?,1532 resource: match RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::ResourceType).ok()? {1533 ResourceType::Basic => RmrkResourceTypes::Basic(RmrkBasicResource {1534 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,1535 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,1536 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,1537 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,1538 }),1539 ResourceType::Composable => RmrkResourceTypes::Composable(RmrkComposableResource {1540 parts: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Parts).ok()?,1541 base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?,1542 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,1543 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,1544 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,1545 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,1546 }),1547 ResourceType::Slot => RmrkResourceTypes::Slot(RmrkSlotResource {1548 base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?,1549 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,1550 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,1551 slot: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Slot).ok()?,1552 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,1553 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,1554 }),1555 },1556 }))1557 .collect();15581559 Ok(resources)1560 }15611562 fn nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Result<Option<u32>, DispatchError> {1563 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};15641565 let collection_id = match RmrkCore::unique_collection_id(collection_id) {1566 Ok(id) => id,1567 Err(_) => return Ok(None)1568 };1569 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(None); }15701571 let nft_id = TokenId(nft_id);1572 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(None); }15731574 let priorities: Vec<_> = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourcePriorities)?;1575 Ok(1576 priorities.into_iter()1577 .enumerate()1578 .find(|(_, id)| *id == resource_id)1579 .map(|(priority, _): (usize, RmrkResourceId)| priority as u32)1580 )1581 }15821583 fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {1584 use pallet_proxy_rmrk_core::{1585 RmrkProperty, misc::{CollectionType},1586 };15871588 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) {1589 Ok(c) => c,1590 Err(_) => return Ok(None),1591 };15921593 Ok(Some(RmrkBaseInfo {1594 issuer: collection.owner.clone(),1595 base_type: RmrkCore::get_collection_property_decoded(collection_id, RmrkProperty::BaseType)?,1596 symbol: RmrkCore::rebind(&collection.token_prefix)?,1597 }))1598 }15991600 fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {1601 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};1602 use pallet_common::CommonCollectionOperations;16031604 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) {1605 Ok(c) => c,1606 Err(_) => return Ok(Vec::new()),1607 };16081609 let parts = collection.collection_tokens()1610 .into_iter()1611 .filter_map(|token_id| {1612 let nft_type = RmrkCore::get_nft_type(collection_id, token_id).ok()?;16131614 match nft_type {1615 NftType::FixedPart => Some(RmrkPartType::FixedPart(RmrkFixedPart {1616 id: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?,1617 src: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::Src).ok()?,1618 z: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ZIndex).ok()?,1619 })),1620 NftType::SlotPart => Some(RmrkPartType::SlotPart(RmrkSlotPart {1621 id: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?,1622 src: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::Src).ok()?,1623 z: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ZIndex).ok()?,1624 equippable: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::EquippableList).ok()?,1625 })),1626 _ => None1627 }1628 })1629 .collect();16301631 Ok(parts)1632 }16331634 fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {1635 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{NftType, CollectionType}};1636 use pallet_common::CommonCollectionOperations;16371638 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) {1639 Ok(c) => c,1640 Err(_) => return Ok(Vec::new()),1641 };16421643 let theme_names = collection.collection_tokens()1644 .iter()1645 .filter_map(|token_id| {1646 let nft_type = RmrkCore::get_nft_type(collection_id, *token_id).ok()?;16471648 match nft_type {1649 NftType::Theme => RmrkCore::get_nft_property_decoded(collection_id, *token_id, RmrkProperty::ThemeName).ok(),1650 _ => None1651 }1652 })1653 .collect();16541655 Ok(theme_names)1656 }16571658 fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {1659 use pallet_proxy_rmrk_core::{1660 RmrkProperty,1661 misc::{CollectionType, NftType}1662 };1663 use pallet_common::CommonCollectionOperations;16641665 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) {1666 Ok(c) => c,1667 Err(_) => return Ok(None),1668 };16691670 let theme_info = collection.collection_tokens()1671 .into_iter()1672 .find_map(|token_id| {1673 RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Theme).ok()?;16741675 let name: RmrkString = RmrkCore::get_nft_property_decoded(1676 collection_id, token_id, RmrkProperty::ThemeName1677 ).ok()?;16781679 if name == theme_name {1680 Some((name, token_id))1681 } else {1682 None1683 }1684 });16851686 let (name, theme_id) = match theme_info {1687 Some((name, theme_id)) => (name, theme_id),1688 None => return Ok(None)1689 };16901691 let properties = RmrkCore::filter_user_properties(1692 collection_id,1693 Some(theme_id),1694 filter_keys,1695 |key, value| RmrkThemeProperty {1696 key,1697 value1698 }1699 )?;17001701 let inherit = RmrkCore::get_nft_property_decoded(1702 collection_id,1703 theme_id,1704 RmrkProperty::ThemeInherit1705 )?;17061707 let theme = RmrkTheme {1708 name,1709 properties,1710 inherit,1711 };17121713 Ok(Some(theme))1714 }1715 }1716}131917171320struct CheckInherents;1718struct CheckInherents;13211719runtime/quartz/src/lib.rsdiffbeforeafterboth1315 }};1315 }};1316}1316}131713171318impl_common_runtime_apis!();1318impl_common_runtime_apis! {1319 #![custom_apis]13201321 impl rmrk_rpc::RmrkApi<1322 Block,1323 AccountId,1324 RmrkCollectionInfo<AccountId>,1325 RmrkInstanceInfo<AccountId>,1326 RmrkResourceInfo,1327 RmrkPropertyInfo,1328 RmrkBaseInfo<AccountId>,1329 RmrkPartType,1330 RmrkTheme1331 > for Runtime {1332 fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {1333 Ok(RmrkCore::last_collection_idx())1334 }13351336 fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {1337 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};1338 use pallet_common::CommonCollectionOperations;13391340 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) {1341 Ok(c) => c,1342 Err(_) => return Ok(None),1343 };13441345 let nfts_count = collection.total_supply();13461347 Ok(Some(RmrkCollectionInfo {1348 issuer: collection.owner.clone(),1349 metadata: RmrkCore::get_collection_property_decoded(collection_id, RmrkProperty::Metadata)?,1350 max: collection.limits.token_limit,1351 symbol: RmrkCore::rebind(&collection.token_prefix)?,1352 nfts_count1353 }))1354 }13551356 fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {1357 use up_data_structs::mapping::TokenAddressMapping;1358 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};1359 use pallet_common::CommonCollectionOperations;13601361 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) {1362 Ok(c) => c,1363 Err(_) => return Ok(None),1364 };13651366 let nft_id = TokenId(nft_by_id);1367 if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(None); }13681369 let owner = match collection.token_owner(nft_id) {1370 Some(owner) => match <Runtime as pallet_common::Config>::CrossTokenAddressMapping::address_to_token(&owner) {1371 Some((col, tok)) => {1372 let rmrk_collection = RmrkCore::rmrk_collection_id(col)?;13731374 RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0)1375 }1376 None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone())1377 },1378 None => return Ok(None)1379 };13801381 Ok(Some(RmrkInstanceInfo {1382 owner: owner,1383 royalty: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::RoyaltyInfo)?,1384 metadata: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Metadata)?,1385 equipped: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Equipped)?,1386 pending: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::PendingNftAccept)?,1387 }))1388 }13891390 fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {1391 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};1392 use pallet_common::CommonCollectionOperations;13931394 let cross_account_id = CrossAccountId::from_sub(account_id);13951396 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) {1397 Ok(c) => c,1398 Err(_) => return Ok(Vec::new()),1399 };14001401 let tokens = collection.account_tokens(cross_account_id)1402 .into_iter()1403 .filter(|token| {1404 let is_pending = RmrkCore::get_nft_property_decoded(1405 collection_id,1406 *token,1407 RmrkProperty::PendingNftAccept1408 ).unwrap_or(true);14091410 !is_pending1411 })1412 .map(|token| token.0)1413 .collect();14141415 Ok(tokens)1416 }14171418 fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {1419 use pallet_proxy_rmrk_core::RmrkProperty;14201421 let collection_id = match RmrkCore::unique_collection_id(collection_id) {1422 Ok(id) => id,1423 Err(_) => return Ok(Vec::new())1424 };1425 let nft_id = TokenId(nft_id);1426 if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(Vec::new()); }14271428 Ok(1429 pallet_nonfungible::TokenChildren::<Runtime>::iter_prefix((collection_id, nft_id))1430 .filter_map(|((child_collection, child_token), _)| {1431 let is_pending = RmrkCore::get_nft_property_decoded(1432 child_collection,1433 child_token,1434 RmrkProperty::PendingNftAccept1435 ).ok()?;14361437 if is_pending {1438 return None;1439 }14401441 let rmrk_child_collection = RmrkCore::rmrk_collection_id(1442 child_collection1443 ).ok()?;14441445 Some(RmrkNftChild {1446 collection_id: rmrk_child_collection,1447 nft_id: child_token.0,1448 })1449 }).collect()1450 )1451 }14521453 fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {1454 use pallet_proxy_rmrk_core::misc::CollectionType;14551456 let collection_id = match RmrkCore::unique_collection_id(collection_id) {1457 Ok(id) => id,1458 Err(_) => return Ok(Vec::new())1459 };1460 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() {1461 return Ok(Vec::new());1462 }14631464 let properties = RmrkCore::filter_user_properties(1465 collection_id,1466 /* token_id = */ None,1467 filter_keys,1468 |key, value| RmrkPropertyInfo {1469 key,1470 value1471 }1472 )?;14731474 Ok(properties)1475 }14761477 fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {1478 use pallet_proxy_rmrk_core::misc::NftType;14791480 let collection_id = match RmrkCore::unique_collection_id(collection_id) {1481 Ok(id) => id,1482 Err(_) => return Ok(Vec::new())1483 };1484 let token_id = TokenId(nft_id);14851486 if RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() {1487 return Ok(Vec::new());1488 }14891490 let properties = RmrkCore::filter_user_properties(1491 collection_id,1492 Some(token_id),1493 filter_keys,1494 |key, value| RmrkPropertyInfo {1495 key,1496 value1497 }1498 )?;14991500 Ok(properties)1501 }15021503 fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {1504 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, ResourceType}};1505 use pallet_common::CommonCollectionOperations;15061507 let collection_id = match RmrkCore::unique_collection_id(collection_id) {1508 Ok(id) => id,1509 Err(_) => return Ok(Vec::new())1510 };1511 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }15121513 let nft_id = TokenId(nft_id);1514 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); }15151516 let res_collection_id: Option<CollectionId> = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)?;15171518 let res_collection_id = match res_collection_id {1519 Some(id) => id,1520 None => return Ok(Vec::new())1521 };15221523 let resource_collection = RmrkCore::get_typed_nft_collection(res_collection_id, CollectionType::Resource)?;15241525 let resources = resource_collection1526 .collection_tokens()1527 .iter()1528 .filter_map(|res_id| Some(RmrkResourceInfo {1529 id: res_id.0,1530 pending: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceAccept).ok()?,1531 pending_removal: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceRemoval).ok()?,1532 resource: match RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::ResourceType).ok()? {1533 ResourceType::Basic => RmrkResourceTypes::Basic(RmrkBasicResource {1534 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,1535 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,1536 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,1537 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,1538 }),1539 ResourceType::Composable => RmrkResourceTypes::Composable(RmrkComposableResource {1540 parts: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Parts).ok()?,1541 base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?,1542 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,1543 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,1544 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,1545 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,1546 }),1547 ResourceType::Slot => RmrkResourceTypes::Slot(RmrkSlotResource {1548 base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?,1549 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,1550 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,1551 slot: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Slot).ok()?,1552 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,1553 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,1554 }),1555 },1556 }))1557 .collect();15581559 Ok(resources)1560 }15611562 fn nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Result<Option<u32>, DispatchError> {1563 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};15641565 let collection_id = match RmrkCore::unique_collection_id(collection_id) {1566 Ok(id) => id,1567 Err(_) => return Ok(None)1568 };1569 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(None); }15701571 let nft_id = TokenId(nft_id);1572 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(None); }15731574 let priorities: Vec<_> = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourcePriorities)?;1575 Ok(1576 priorities.into_iter()1577 .enumerate()1578 .find(|(_, id)| *id == resource_id)1579 .map(|(priority, _): (usize, RmrkResourceId)| priority as u32)1580 )1581 }15821583 fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {1584 use pallet_proxy_rmrk_core::{1585 RmrkProperty, misc::{CollectionType},1586 };15871588 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) {1589 Ok(c) => c,1590 Err(_) => return Ok(None),1591 };15921593 Ok(Some(RmrkBaseInfo {1594 issuer: collection.owner.clone(),1595 base_type: RmrkCore::get_collection_property_decoded(collection_id, RmrkProperty::BaseType)?,1596 symbol: RmrkCore::rebind(&collection.token_prefix)?,1597 }))1598 }15991600 fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {1601 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};1602 use pallet_common::CommonCollectionOperations;16031604 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) {1605 Ok(c) => c,1606 Err(_) => return Ok(Vec::new()),1607 };16081609 let parts = collection.collection_tokens()1610 .into_iter()1611 .filter_map(|token_id| {1612 let nft_type = RmrkCore::get_nft_type(collection_id, token_id).ok()?;16131614 match nft_type {1615 NftType::FixedPart => Some(RmrkPartType::FixedPart(RmrkFixedPart {1616 id: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?,1617 src: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::Src).ok()?,1618 z: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ZIndex).ok()?,1619 })),1620 NftType::SlotPart => Some(RmrkPartType::SlotPart(RmrkSlotPart {1621 id: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?,1622 src: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::Src).ok()?,1623 z: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ZIndex).ok()?,1624 equippable: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::EquippableList).ok()?,1625 })),1626 _ => None1627 }1628 })1629 .collect();16301631 Ok(parts)1632 }16331634 fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {1635 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{NftType, CollectionType}};1636 use pallet_common::CommonCollectionOperations;16371638 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) {1639 Ok(c) => c,1640 Err(_) => return Ok(Vec::new()),1641 };16421643 let theme_names = collection.collection_tokens()1644 .iter()1645 .filter_map(|token_id| {1646 let nft_type = RmrkCore::get_nft_type(collection_id, *token_id).ok()?;16471648 match nft_type {1649 NftType::Theme => RmrkCore::get_nft_property_decoded(collection_id, *token_id, RmrkProperty::ThemeName).ok(),1650 _ => None1651 }1652 })1653 .collect();16541655 Ok(theme_names)1656 }16571658 fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {1659 use pallet_proxy_rmrk_core::{1660 RmrkProperty,1661 misc::{CollectionType, NftType}1662 };1663 use pallet_common::CommonCollectionOperations;16641665 let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) {1666 Ok(c) => c,1667 Err(_) => return Ok(None),1668 };16691670 let theme_info = collection.collection_tokens()1671 .into_iter()1672 .find_map(|token_id| {1673 RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Theme).ok()?;16741675 let name: RmrkString = RmrkCore::get_nft_property_decoded(1676 collection_id, token_id, RmrkProperty::ThemeName1677 ).ok()?;16781679 if name == theme_name {1680 Some((name, token_id))1681 } else {1682 None1683 }1684 });16851686 let (name, theme_id) = match theme_info {1687 Some((name, theme_id)) => (name, theme_id),1688 None => return Ok(None)1689 };16901691 let properties = RmrkCore::filter_user_properties(1692 collection_id,1693 Some(theme_id),1694 filter_keys,1695 |key, value| RmrkThemeProperty {1696 key,1697 value1698 }1699 )?;17001701 let inherit = RmrkCore::get_nft_property_decoded(1702 collection_id,1703 theme_id,1704 RmrkProperty::ThemeInherit1705 )?;17061707 let theme = RmrkTheme {1708 name,1709 properties,1710 inherit,1711 };17121713 Ok(Some(theme))1714 }1715 }1716}131917171320struct CheckInherents;1718struct CheckInherents;13211719runtime/unique/src/lib.rsdiffbeforeafterboth74 CollectionStats, RpcCollection,74 CollectionStats, RpcCollection,75 mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},75 mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},76 TokenChild, RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo,76 TokenChild, RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo,77 RmrkBaseInfo, RmrkPartType, RmrkTheme, RmrkThemeName, RmrkThemeProperty, RmrkCollectionId,77 RmrkBaseInfo, RmrkPartType, RmrkTheme, RmrkThemeName, RmrkCollectionId,78 RmrkNftId, RmrkAccountIdOrCollectionNftTuple, RmrkNftChild, RmrkPropertyKey, RmrkResourceTypes,78 RmrkNftId, RmrkNftChild, RmrkPropertyKey,79 RmrkBasicResource, RmrkComposableResource, RmrkSlotResource, RmrkResourceId, RmrkBaseId,79 RmrkResourceId, RmrkBaseId,80 RmrkFixedPart, RmrkSlotPart, RmrkString,81};80};828183// use pallet_contracts::weights::WeightInfo;82// use pallet_contracts::weights::WeightInfo;916 type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;915 type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;917}916}918919impl pallet_proxy_rmrk_core::Config for Runtime {920 type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight<Self>;921 type Event = Event;922}923924impl pallet_proxy_rmrk_equip::Config for Runtime {925 type Event = Event;926}927917928impl pallet_unique::Config for Runtime {918impl pallet_unique::Config for Runtime {929 type Event = Event;919 type Event = Event;1164 Refungible: pallet_refungible::{Pallet, Storage} = 68,1154 Refungible: pallet_refungible::{Pallet, Storage} = 68,1165 Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69,1155 Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69,1166 Structure: pallet_structure::{Pallet, Call, Storage, Event<T>} = 70,1156 Structure: pallet_structure::{Pallet, Call, Storage, Event<T>} = 70,1167 RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event<T>} = 71,1168 RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event<T>} = 72,116911571170 // Frontier1158 // Frontier1171 EVM: pallet_evm::{Pallet, Config, Call, Storage, Event<T>} = 100,1159 EVM: pallet_evm::{Pallet, Config, Call, Storage, Event<T>} = 100,1313 }};1301 }};1314}1302}131513031316impl_common_runtime_apis!();1304impl_common_runtime_apis! {1305 #![custom_apis]13061307 impl rmrk_rpc::RmrkApi<1308 Block,1309 AccountId,1310 RmrkCollectionInfo<AccountId>,1311 RmrkInstanceInfo<AccountId>,1312 RmrkResourceInfo,1313 RmrkPropertyInfo,1314 RmrkBaseInfo<AccountId>,1315 RmrkPartType,1316 RmrkTheme1317 > for Runtime {1318 fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {1319 Ok(Default::default())1320 }13211322 fn collection_by_id(_collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {1323 Ok(Default::default())1324 }13251326 fn nft_by_id(_collection_id: RmrkCollectionId, _nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {1327 Ok(Default::default())1328 }13291330 fn account_tokens(_account_id: AccountId, _collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {1331 Ok(Default::default())1332 }13331334 fn nft_children(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {1335 Ok(Default::default())1336 }13371338 fn collection_properties(_collection_id: RmrkCollectionId, _filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {1339 Ok(Default::default())1340 }13411342 fn nft_properties(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId, _filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {1343 Ok(Default::default())1344 }13451346 fn nft_resources(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {1347 Ok(Default::default())1348 }13491350 fn nft_resource_priority(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId, _resource_id: RmrkResourceId) -> Result<Option<u32>, DispatchError> {1351 Ok(Default::default())1352 }13531354 fn base(_base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {1355 Ok(Default::default())1356 }13571358 fn base_parts(_base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {1359 Ok(Default::default())1360 }13611362 fn theme_names(_base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {1363 Ok(Default::default())1364 }13651366 fn theme(_base_id: RmrkBaseId, _theme_name: RmrkThemeName, _filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {1367 Ok(Default::default())1368 }1369 }1370}131713711318struct CheckInherents;1372struct CheckInherents;13191373tests/src/eth/nesting/nest.test.tsdiffbeforeafterboth29 const {collectionId, contract} = await createNestingCollection(api, web3, owner);29 const {collectionId, contract} = await createNestingCollection(api, web3, owner);303031 // Create a token to be nested31 // Create a token to be nested32 const nftTokenId = await contract.methods.nextTokenId().call();32 const targetNFTTokenId = await contract.methods.nextTokenId().call();33 await contract.methods.mint(33 await contract.methods.mint(34 owner,34 owner,35 nftTokenId,35 targetNFTTokenId,36 ).send({from: owner});36 ).send({from: owner});3738 const targetNftTokenAddress = tokenIdToAddress(collectionId, targetNFTTokenId);373938 // Nest into a token40 // Create a nested token39 const firstTargetNftTokenId = await contract.methods.nextTokenId().call();41 const firstTokenId = await contract.methods.nextTokenId().call();40 await contract.methods.mint(42 await contract.methods.mint(41 owner,43 targetNftTokenAddress,42 firstTargetNftTokenId,44 firstTokenId,43 ).send({from: owner});45 ).send({from: owner});444645 const targetNftTokenAddress = tokenIdToAddress(collectionId, firstTargetNftTokenId);4647 await contract.methods.transfer(targetNftTokenAddress, nftTokenId).send({from: owner});48 expect(await contract.methods.ownerOf(nftTokenId).call()).to.be.equal(targetNftTokenAddress);47 expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress);494850 // Re-nest into another49 // Create a token to be nested and nest51 const secondTargetNftTokenId = await contract.methods.nextTokenId().call();50 const secondTokenId = await contract.methods.nextTokenId().call();52 await contract.methods.mint(51 await contract.methods.mint(53 owner,52 owner,54 secondTargetNftTokenId,53 secondTokenId,55 ).send({from: owner});54 ).send({from: owner});5556 const nextNftTokenAddress = tokenIdToAddress(collectionId, secondTargetNftTokenId);56 await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner});575758 expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress);5960 // Unnest token back58 await contract.methods.transfer(nextNftTokenAddress, nftTokenId).send({from: owner});61 await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner});59 expect(await contract.methods.ownerOf(nftTokenId).call()).to.be.equal(nextNftTokenAddress);62 expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner);60 });63 });616462 itWeb3('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => {65 itWeb3('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => {tests/src/nesting/nest.test.tsdiffbeforeafterboth454 it('Admin (NFT): disallows an Admin to nest and unnest someone else\'s token', async () => {454 it('Admin (NFT): disallows an Admin to nest and unnest someone else\'s token', async () => {455 await usingApi(async api => {455 await usingApi(async api => {456 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});456 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});457 await setCollectionLimitsExpectSuccess(alice, collection, {ownerCanTransfer: true});457 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});458 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}});458459459 await addToAllowListExpectSuccess(alice, collection, bob.address);460 await addToAllowListExpectSuccess(alice, collection, bob.address);tests/src/pallet-presence.test.tsdiffbeforeafterboth50 'unique',50 'unique',51 'nonfungible',51 'nonfungible',52 'refungible',52 'refungible',53 'rmrkcore',54 'rmrkequip',55 'scheduler',53 'scheduler',56 'charging',54 'charging',57];55];64];62];656366describe('Pallet presence', () => {64describe('Pallet presence', () => {65 before(async () => {66 await usingApi(async api => {67 const chain = await api.rpc.system.chain();6869 if (!chain.eq('UNIQUE')) {70 requiredPallets.push(...['rmrkcore', 'rmrkequip']);71 }72 });73 });7467 it('Required pallets are present', async () => {75 it('Required pallets are present', async () => {68 await usingApi(async api => {76 await usingApi(async api => {tests/src/rmrk/rmrk.test.tsdiffbeforeafterboth11} from '../util/helpers';11} from '../util/helpers';12import {IKeyringPair} from '@polkadot/types/types';12import {IKeyringPair} from '@polkadot/types/types';13import {ApiPromise} from '@polkadot/api';13import {ApiPromise} from '@polkadot/api';14import {it} from 'mocha';141515let alice: IKeyringPair;16let alice: IKeyringPair;16let bob: IKeyringPair;17let bob: IKeyringPair;48 return result.data!;49 return result.data!;49}50}5152async function isUnique(): Promise<boolean> {53 return usingApi(async api => {54 const chain = await api.rpc.system.chain();5556 return chain.eq('UNIQUE');57 });58}505951describe('RMRK External Integration Test', () => {60describe('RMRK External Integration Test', async () => {61 const it_rmrk = (await isUnique() ? it : it.skip);6252 before(async () => {63 before(async () => {53 await usingApi(async (api, privateKeyWrapper) => {64 await usingApi(async (api, privateKeyWrapper) => {54 alice = privateKeyWrapper('//Alice');65 alice = privateKeyWrapper('//Alice');6667 55 });68 });56 });69 });577058 it('Creates a new RMRK collection that is mapped to a different ID and is tagged as external', async () => {71 it_rmrk('Creates a new RMRK collection that is mapped to a different ID and is tagged as external', async () => {59 await usingApi(async api => {72 await usingApi(async api => {60 // throwaway collection to bump last Unique collection ID to test ID mapping73 // throwaway collection to bump last Unique collection ID to test ID mapping61 await createCollectionExpectSuccess();74 await createCollectionExpectSuccess();70 });83 });71});84});728573describe('Negative Integration Test: External Collections, Internal Ops', () => {86describe('Negative Integration Test: External Collections, Internal Ops', async () => {74 let uniqueCollectionId: number;87 let uniqueCollectionId: number;75 let rmrkCollectionId: number;88 let rmrkCollectionId: number;76 let rmrkNftId: number;89 let rmrkNftId: number;9091 const it_rmrk = (await isUnique() ? it : it.skip);779278 before(async () => {93 before(async () => {79 await usingApi(async (api, privateKeyWrapper) => {94 await usingApi(async (api, privateKeyWrapper) => {88 });103 });89 });104 });9010591 it('[Negative] Forbids Unique operations with an external collection, handled by dispatch_call', async () => {106 it_rmrk('[Negative] Forbids Unique operations with an external collection, handled by dispatch_call', async () => {92 await usingApi(async api => {107 await usingApi(async api => {93 // Collection item creation108 // Collection item creation94109147 });162 });148 });163 });149164150 it('[Negative] Forbids Unique collection operations with an external collection', async () => {165 it_rmrk('[Negative] Forbids Unique collection operations with an external collection', async () => {151 await usingApi(async api => {166 await usingApi(async api => {152 const txDestroyCollection = api.tx.unique.destroyCollection(uniqueCollectionId);167 const txDestroyCollection = api.tx.unique.destroyCollection(uniqueCollectionId);153 await expect(executeTransaction(api, alice, txDestroyCollection), 'destroying collection')168 await expect(executeTransaction(api, alice, txDestroyCollection), 'destroying collection')206 });221 });207});222});208223209describe('Negative Integration Test: Internal Collections, External Ops', () => {224describe('Negative Integration Test: Internal Collections, External Ops', async () => {210 let collectionId: number;225 let collectionId: number;211 let nftId: number;226 let nftId: number;227228 const it_rmrk = (await isUnique() ? it : it.skip);212229213 before(async () => {230 before(async () => {214 await usingApi(async (api, privateKeyWrapper) => {231 await usingApi(async (api, privateKeyWrapper) => {220 });237 });221 });238 });222239223 it('[Negative] Forbids RMRK operations with the internal collection and NFT (due to the lack of mapping)', async () => {240 it_rmrk('[Negative] Forbids RMRK operations with the internal collection and NFT (due to the lack of mapping)', async () => {224 await usingApi(async api => {241 await usingApi(async api => {225 const txChangeOwner = api.tx.rmrkCore.changeCollectionIssuer(collectionId, bob.address);242 const txChangeOwner = api.tx.rmrkCore.changeCollectionIssuer(collectionId, bob.address);226 await expect(executeTransaction(api, alice, txChangeOwner), 'changing collection issuer')243 await expect(executeTransaction(api, alice, txChangeOwner), 'changing collection issuer')