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

difftreelog

Merge pull request #385 from UniqueNetwork/feature/conditional-rmrk

kozyrevdev2022-06-14parents: #32f061e #0df5b01.patch.diff
in: master
feat(rmrk): remove RMRK proxy from unique runtime

10 files changed

modifiednode/rpc/Cargo.tomldiffbeforeafterboth
63[features]63[features]
64default = []64default = []
65std = []65std = []
66unique-runtime = []
6667
modifiednode/rpc/src/lib.rsdiffbeforeafterboth
169 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};
173
174 #[cfg(not(feature = "unique-runtime"))]
175 use uc_rpc::{RmrkApiServer, Rmrk};
176
173 // 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};
224228
225 io.merge(Unique::new(client.clone()).into_rpc())?;229 io.merge(Unique::new(client.clone()).into_rpc())?;
230
231 #[cfg(not(feature = "unique-runtime"))]
226 io.merge(Rmrk::new(client.clone()).into_rpc())?;232 io.merge(Rmrk::new(client.clone()).into_rpc())?;
227233
228 if let Some(filter_pool) = filter_pool {234 if let Some(filter_pool) = filter_pool {
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
144 }144 }
145 }145 }
146
147 impl rmrk_rpc::RmrkApi<
148 Block,
149 AccountId,
150 RmrkCollectionInfo<AccountId>,
151 RmrkInstanceInfo<AccountId>,
152 RmrkResourceInfo,
153 RmrkPropertyInfo,
154 RmrkBaseInfo<AccountId>,
155 RmrkPartType,
156 RmrkTheme
157 > for Runtime {
158 fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {
159 Ok(RmrkCore::last_collection_idx())
160 }
161
162 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;
165
166 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 };
170
171 let nfts_count = collection.total_supply();
172
173 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_count
179 }))
180 }
181
182 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;
186
187 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 };
191
192 let nft_id = TokenId(nft_by_id);
193 if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(None); }
194
195 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)?;
199
200 RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0)
201 }
202 None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone())
203 },
204 None => return Ok(None)
205 };
206
207 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 }
215
216 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;
219
220 let cross_account_id = CrossAccountId::from_sub(account_id);
221
222 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 };
226
227 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::PendingNftAccept
234 ).unwrap_or(true);
235
236 !is_pending
237 })
238 .map(|token| token.0)
239 .collect();
240
241 Ok(tokens)
242 }
243
244 fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
245 use pallet_proxy_rmrk_core::RmrkProperty;
246
247 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()); }
253
254 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::PendingNftAccept
261 ).ok()?;
262
263 if is_pending {
264 return None;
265 }
266
267 let rmrk_child_collection = RmrkCore::rmrk_collection_id(
268 child_collection
269 ).ok()?;
270
271 Some(RmrkNftChild {
272 collection_id: rmrk_child_collection,
273 nft_id: child_token.0,
274 })
275 }).collect()
276 )
277 }
278
279 fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
280 use pallet_proxy_rmrk_core::misc::CollectionType;
281
282 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 }
289
290 let properties = RmrkCore::filter_user_properties(
291 collection_id,
292 /* token_id = */ None,
293 filter_keys,
294 |key, value| RmrkPropertyInfo {
295 key,
296 value
297 }
298 )?;
299
300 Ok(properties)
301 }
302
303 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;
305
306 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);
311
312 if RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() {
313 return Ok(Vec::new());
314 }
315
316 let properties = RmrkCore::filter_user_properties(
317 collection_id,
318 Some(token_id),
319 filter_keys,
320 |key, value| RmrkPropertyInfo {
321 key,
322 value
323 }
324 )?;
325
326 Ok(properties)
327 }
328
329 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;
332
333 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()); }
338
339 let nft_id = TokenId(nft_id);
340 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); }
341
342 let res_collection_id: Option<CollectionId> = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)?;
343
344 let res_collection_id = match res_collection_id {
345 Some(id) => id,
346 None => return Ok(Vec::new())
347 };
348
349 let resource_collection = RmrkCore::get_typed_nft_collection(res_collection_id, CollectionType::Resource)?;
350
351 let resources = resource_collection
352 .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();
384
385 Ok(resources)
386 }
387
388 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}};
390
391 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); }
396
397 let nft_id = TokenId(nft_id);
398 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(None); }
399
400 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 }
408
409 fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
410 use pallet_proxy_rmrk_core::{
411 RmrkProperty, misc::{CollectionType},
412 };
413
414 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 };
418
419 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 }
425
426 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;
429
430 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 };
434
435 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()?;
439
440 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 _ => None
453 }
454 })
455 .collect();
456
457 Ok(parts)
458 }
459
460 fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
461 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};
462 use pallet_common::CommonCollectionOperations;
463
464 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 };
468
469 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()?;
473
474 match nft_type {
475 Theme => RmrkCore::get_nft_property_decoded(collection_id, *token_id, RmrkProperty::ThemeName).ok(),
476 _ => None
477 }
478 })
479 .collect();
480
481 Ok(theme_names)
482 }
483
484 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;
490
491 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 };
495
496 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()?;
500
501 let name: RmrkString = RmrkCore::get_nft_property_decoded(
502 collection_id, token_id, RmrkProperty::ThemeName
503 ).ok()?;
504
505 if name == theme_name {
506 Some((name, token_id))
507 } else {
508 None
509 }
510 });
511
512 let (name, theme_id) = match theme_info {
513 Some((name, theme_id)) => (name, theme_id),
514 None => return Ok(None)
515 };
516
517 let properties = RmrkCore::filter_user_properties(
518 collection_id,
519 Some(theme_id),
520 filter_keys,
521 |key, value| RmrkThemeProperty {
522 key,
523 value
524 }
525 )?;
526
527 let inherit = RmrkCore::get_nft_property_decoded(
528 collection_id,
529 theme_id,
530 RmrkProperty::ThemeInherit
531 )?;
532
533 let theme = RmrkTheme {
534 name,
535 properties,
536 inherit,
537 };
538
539 Ok(Some(theme))
540 }
541 }
542146
543 impl sp_api::Core<Block> for Runtime {147 impl sp_api::Core<Block> for Runtime {
544 fn version() -> RuntimeVersion {148 fn version() -> RuntimeVersion {
modifiedruntime/opal/src/lib.rsdiffbeforeafterboth
1315 }};1315 }};
1316}1316}
13171317
1318impl_common_runtime_apis!();1318impl_common_runtime_apis! {
1319 #![custom_apis]
1320
1321 impl rmrk_rpc::RmrkApi<
1322 Block,
1323 AccountId,
1324 RmrkCollectionInfo<AccountId>,
1325 RmrkInstanceInfo<AccountId>,
1326 RmrkResourceInfo,
1327 RmrkPropertyInfo,
1328 RmrkBaseInfo<AccountId>,
1329 RmrkPartType,
1330 RmrkTheme
1331 > for Runtime {
1332 fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {
1333 Ok(RmrkCore::last_collection_idx())
1334 }
1335
1336 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;
1339
1340 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 };
1344
1345 let nfts_count = collection.total_supply();
1346
1347 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_count
1353 }))
1354 }
1355
1356 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;
1360
1361 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 };
1365
1366 let nft_id = TokenId(nft_by_id);
1367 if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(None); }
1368
1369 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)?;
1373
1374 RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0)
1375 }
1376 None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone())
1377 },
1378 None => return Ok(None)
1379 };
1380
1381 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 }
1389
1390 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;
1393
1394 let cross_account_id = CrossAccountId::from_sub(account_id);
1395
1396 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 };
1400
1401 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::PendingNftAccept
1408 ).unwrap_or(true);
1409
1410 !is_pending
1411 })
1412 .map(|token| token.0)
1413 .collect();
1414
1415 Ok(tokens)
1416 }
1417
1418 fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
1419 use pallet_proxy_rmrk_core::RmrkProperty;
1420
1421 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()); }
1427
1428 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::PendingNftAccept
1435 ).ok()?;
1436
1437 if is_pending {
1438 return None;
1439 }
1440
1441 let rmrk_child_collection = RmrkCore::rmrk_collection_id(
1442 child_collection
1443 ).ok()?;
1444
1445 Some(RmrkNftChild {
1446 collection_id: rmrk_child_collection,
1447 nft_id: child_token.0,
1448 })
1449 }).collect()
1450 )
1451 }
1452
1453 fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
1454 use pallet_proxy_rmrk_core::misc::CollectionType;
1455
1456 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 }
1463
1464 let properties = RmrkCore::filter_user_properties(
1465 collection_id,
1466 /* token_id = */ None,
1467 filter_keys,
1468 |key, value| RmrkPropertyInfo {
1469 key,
1470 value
1471 }
1472 )?;
1473
1474 Ok(properties)
1475 }
1476
1477 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;
1479
1480 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);
1485
1486 if RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() {
1487 return Ok(Vec::new());
1488 }
1489
1490 let properties = RmrkCore::filter_user_properties(
1491 collection_id,
1492 Some(token_id),
1493 filter_keys,
1494 |key, value| RmrkPropertyInfo {
1495 key,
1496 value
1497 }
1498 )?;
1499
1500 Ok(properties)
1501 }
1502
1503 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;
1506
1507 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()); }
1512
1513 let nft_id = TokenId(nft_id);
1514 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); }
1515
1516 let res_collection_id: Option<CollectionId> = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)?;
1517
1518 let res_collection_id = match res_collection_id {
1519 Some(id) => id,
1520 None => return Ok(Vec::new())
1521 };
1522
1523 let resource_collection = RmrkCore::get_typed_nft_collection(res_collection_id, CollectionType::Resource)?;
1524
1525 let resources = resource_collection
1526 .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();
1558
1559 Ok(resources)
1560 }
1561
1562 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}};
1564
1565 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); }
1570
1571 let nft_id = TokenId(nft_id);
1572 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(None); }
1573
1574 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 }
1582
1583 fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
1584 use pallet_proxy_rmrk_core::{
1585 RmrkProperty, misc::{CollectionType},
1586 };
1587
1588 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 };
1592
1593 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 }
1599
1600 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;
1603
1604 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 };
1608
1609 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()?;
1613
1614 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 _ => None
1627 }
1628 })
1629 .collect();
1630
1631 Ok(parts)
1632 }
1633
1634 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;
1637
1638 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 };
1642
1643 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()?;
1647
1648 match nft_type {
1649 NftType::Theme => RmrkCore::get_nft_property_decoded(collection_id, *token_id, RmrkProperty::ThemeName).ok(),
1650 _ => None
1651 }
1652 })
1653 .collect();
1654
1655 Ok(theme_names)
1656 }
1657
1658 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;
1664
1665 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 };
1669
1670 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()?;
1674
1675 let name: RmrkString = RmrkCore::get_nft_property_decoded(
1676 collection_id, token_id, RmrkProperty::ThemeName
1677 ).ok()?;
1678
1679 if name == theme_name {
1680 Some((name, token_id))
1681 } else {
1682 None
1683 }
1684 });
1685
1686 let (name, theme_id) = match theme_info {
1687 Some((name, theme_id)) => (name, theme_id),
1688 None => return Ok(None)
1689 };
1690
1691 let properties = RmrkCore::filter_user_properties(
1692 collection_id,
1693 Some(theme_id),
1694 filter_keys,
1695 |key, value| RmrkThemeProperty {
1696 key,
1697 value
1698 }
1699 )?;
1700
1701 let inherit = RmrkCore::get_nft_property_decoded(
1702 collection_id,
1703 theme_id,
1704 RmrkProperty::ThemeInherit
1705 )?;
1706
1707 let theme = RmrkTheme {
1708 name,
1709 properties,
1710 inherit,
1711 };
1712
1713 Ok(Some(theme))
1714 }
1715 }
1716}
13191717
1320struct CheckInherents;1718struct CheckInherents;
13211719
modifiedruntime/quartz/src/lib.rsdiffbeforeafterboth
1315 }};1315 }};
1316}1316}
13171317
1318impl_common_runtime_apis!();1318impl_common_runtime_apis! {
1319 #![custom_apis]
1320
1321 impl rmrk_rpc::RmrkApi<
1322 Block,
1323 AccountId,
1324 RmrkCollectionInfo<AccountId>,
1325 RmrkInstanceInfo<AccountId>,
1326 RmrkResourceInfo,
1327 RmrkPropertyInfo,
1328 RmrkBaseInfo<AccountId>,
1329 RmrkPartType,
1330 RmrkTheme
1331 > for Runtime {
1332 fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {
1333 Ok(RmrkCore::last_collection_idx())
1334 }
1335
1336 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;
1339
1340 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 };
1344
1345 let nfts_count = collection.total_supply();
1346
1347 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_count
1353 }))
1354 }
1355
1356 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;
1360
1361 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 };
1365
1366 let nft_id = TokenId(nft_by_id);
1367 if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(None); }
1368
1369 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)?;
1373
1374 RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0)
1375 }
1376 None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone())
1377 },
1378 None => return Ok(None)
1379 };
1380
1381 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 }
1389
1390 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;
1393
1394 let cross_account_id = CrossAccountId::from_sub(account_id);
1395
1396 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 };
1400
1401 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::PendingNftAccept
1408 ).unwrap_or(true);
1409
1410 !is_pending
1411 })
1412 .map(|token| token.0)
1413 .collect();
1414
1415 Ok(tokens)
1416 }
1417
1418 fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
1419 use pallet_proxy_rmrk_core::RmrkProperty;
1420
1421 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()); }
1427
1428 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::PendingNftAccept
1435 ).ok()?;
1436
1437 if is_pending {
1438 return None;
1439 }
1440
1441 let rmrk_child_collection = RmrkCore::rmrk_collection_id(
1442 child_collection
1443 ).ok()?;
1444
1445 Some(RmrkNftChild {
1446 collection_id: rmrk_child_collection,
1447 nft_id: child_token.0,
1448 })
1449 }).collect()
1450 )
1451 }
1452
1453 fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
1454 use pallet_proxy_rmrk_core::misc::CollectionType;
1455
1456 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 }
1463
1464 let properties = RmrkCore::filter_user_properties(
1465 collection_id,
1466 /* token_id = */ None,
1467 filter_keys,
1468 |key, value| RmrkPropertyInfo {
1469 key,
1470 value
1471 }
1472 )?;
1473
1474 Ok(properties)
1475 }
1476
1477 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;
1479
1480 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);
1485
1486 if RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() {
1487 return Ok(Vec::new());
1488 }
1489
1490 let properties = RmrkCore::filter_user_properties(
1491 collection_id,
1492 Some(token_id),
1493 filter_keys,
1494 |key, value| RmrkPropertyInfo {
1495 key,
1496 value
1497 }
1498 )?;
1499
1500 Ok(properties)
1501 }
1502
1503 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;
1506
1507 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()); }
1512
1513 let nft_id = TokenId(nft_id);
1514 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); }
1515
1516 let res_collection_id: Option<CollectionId> = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)?;
1517
1518 let res_collection_id = match res_collection_id {
1519 Some(id) => id,
1520 None => return Ok(Vec::new())
1521 };
1522
1523 let resource_collection = RmrkCore::get_typed_nft_collection(res_collection_id, CollectionType::Resource)?;
1524
1525 let resources = resource_collection
1526 .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();
1558
1559 Ok(resources)
1560 }
1561
1562 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}};
1564
1565 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); }
1570
1571 let nft_id = TokenId(nft_id);
1572 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(None); }
1573
1574 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 }
1582
1583 fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
1584 use pallet_proxy_rmrk_core::{
1585 RmrkProperty, misc::{CollectionType},
1586 };
1587
1588 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 };
1592
1593 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 }
1599
1600 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;
1603
1604 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 };
1608
1609 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()?;
1613
1614 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 _ => None
1627 }
1628 })
1629 .collect();
1630
1631 Ok(parts)
1632 }
1633
1634 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;
1637
1638 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 };
1642
1643 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()?;
1647
1648 match nft_type {
1649 NftType::Theme => RmrkCore::get_nft_property_decoded(collection_id, *token_id, RmrkProperty::ThemeName).ok(),
1650 _ => None
1651 }
1652 })
1653 .collect();
1654
1655 Ok(theme_names)
1656 }
1657
1658 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;
1664
1665 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 };
1669
1670 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()?;
1674
1675 let name: RmrkString = RmrkCore::get_nft_property_decoded(
1676 collection_id, token_id, RmrkProperty::ThemeName
1677 ).ok()?;
1678
1679 if name == theme_name {
1680 Some((name, token_id))
1681 } else {
1682 None
1683 }
1684 });
1685
1686 let (name, theme_id) = match theme_info {
1687 Some((name, theme_id)) => (name, theme_id),
1688 None => return Ok(None)
1689 };
1690
1691 let properties = RmrkCore::filter_user_properties(
1692 collection_id,
1693 Some(theme_id),
1694 filter_keys,
1695 |key, value| RmrkThemeProperty {
1696 key,
1697 value
1698 }
1699 )?;
1700
1701 let inherit = RmrkCore::get_nft_property_decoded(
1702 collection_id,
1703 theme_id,
1704 RmrkProperty::ThemeInherit
1705 )?;
1706
1707 let theme = RmrkTheme {
1708 name,
1709 properties,
1710 inherit,
1711 };
1712
1713 Ok(Some(theme))
1714 }
1715 }
1716}
13191717
1320struct CheckInherents;1718struct CheckInherents;
13211719
modifiedruntime/unique/src/lib.rsdiffbeforeafterboth
74 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};
8281
83// 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}
918
919impl pallet_proxy_rmrk_core::Config for Runtime {
920 type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight<Self>;
921 type Event = Event;
922}
923
924impl pallet_proxy_rmrk_equip::Config for Runtime {
925 type Event = Event;
926}
927917
928impl 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,
11691157
1170 // Frontier1158 // Frontier
1171 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}
13151303
1316impl_common_runtime_apis!();1304impl_common_runtime_apis! {
1305 #![custom_apis]
1306
1307 impl rmrk_rpc::RmrkApi<
1308 Block,
1309 AccountId,
1310 RmrkCollectionInfo<AccountId>,
1311 RmrkInstanceInfo<AccountId>,
1312 RmrkResourceInfo,
1313 RmrkPropertyInfo,
1314 RmrkBaseInfo<AccountId>,
1315 RmrkPartType,
1316 RmrkTheme
1317 > for Runtime {
1318 fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {
1319 Ok(Default::default())
1320 }
1321
1322 fn collection_by_id(_collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {
1323 Ok(Default::default())
1324 }
1325
1326 fn nft_by_id(_collection_id: RmrkCollectionId, _nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {
1327 Ok(Default::default())
1328 }
1329
1330 fn account_tokens(_account_id: AccountId, _collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {
1331 Ok(Default::default())
1332 }
1333
1334 fn nft_children(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
1335 Ok(Default::default())
1336 }
1337
1338 fn collection_properties(_collection_id: RmrkCollectionId, _filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
1339 Ok(Default::default())
1340 }
1341
1342 fn nft_properties(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId, _filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
1343 Ok(Default::default())
1344 }
1345
1346 fn nft_resources(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
1347 Ok(Default::default())
1348 }
1349
1350 fn nft_resource_priority(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId, _resource_id: RmrkResourceId) -> Result<Option<u32>, DispatchError> {
1351 Ok(Default::default())
1352 }
1353
1354 fn base(_base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
1355 Ok(Default::default())
1356 }
1357
1358 fn base_parts(_base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
1359 Ok(Default::default())
1360 }
1361
1362 fn theme_names(_base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
1363 Ok(Default::default())
1364 }
1365
1366 fn theme(_base_id: RmrkBaseId, _theme_name: RmrkThemeName, _filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {
1367 Ok(Default::default())
1368 }
1369 }
1370}
13171371
1318struct CheckInherents;1372struct CheckInherents;
13191373
modifiedtests/src/eth/nesting/nest.test.tsdiffbeforeafterboth
29 const {collectionId, contract} = await createNestingCollection(api, web3, owner);29 const {collectionId, contract} = await createNestingCollection(api, web3, owner);
3030
31 // Create a token to be nested31 // Create a token to be nested
32 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});
37
38 const targetNftTokenAddress = tokenIdToAddress(collectionId, targetNFTTokenId);
3739
38 // Nest into a token40 // Create a nested token
39 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});
4446
45 const targetNftTokenAddress = tokenIdToAddress(collectionId, firstTargetNftTokenId);
46
47 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);
4948
50 // Re-nest into another49 // Create a token to be nested and nest
51 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});
55
56 const nextNftTokenAddress = tokenIdToAddress(collectionId, secondTargetNftTokenId);56 await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner});
5757
58 expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress);
59
60 // Unnest token back
58 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 });
6164
62 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}) => {
modifiedtests/src/nesting/nest.test.tsdiffbeforeafterboth
454 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}});
458459
459 await addToAllowListExpectSuccess(alice, collection, bob.address);460 await addToAllowListExpectSuccess(alice, collection, bob.address);
modifiedtests/src/pallet-presence.test.tsdiffbeforeafterboth
50 '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];
6563
66describe('Pallet presence', () => {64describe('Pallet presence', () => {
65 before(async () => {
66 await usingApi(async api => {
67 const chain = await api.rpc.system.chain();
68
69 if (!chain.eq('UNIQUE')) {
70 requiredPallets.push(...['rmrkcore', 'rmrkequip']);
71 }
72 });
73 });
74
67 it('Required pallets are present', async () => {75 it('Required pallets are present', async () => {
68 await usingApi(async api => {76 await usingApi(async api => {
modifiedtests/src/rmrk/rmrk.test.tsdiffbeforeafterboth
11} 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';
1415
15let alice: IKeyringPair;16let alice: IKeyringPair;
16let bob: IKeyringPair;17let bob: IKeyringPair;
48 return result.data!;49 return result.data!;
49}50}
51
52async function isUnique(): Promise<boolean> {
53 return usingApi(async api => {
54 const chain = await api.rpc.system.chain();
55
56 return chain.eq('UNIQUE');
57 });
58}
5059
51describe('RMRK External Integration Test', () => {60describe('RMRK External Integration Test', async () => {
61 const it_rmrk = (await isUnique() ? it : it.skip);
62
52 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');
66
67
55 });68 });
56 });69 });
5770
58 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 mapping
61 await createCollectionExpectSuccess();74 await createCollectionExpectSuccess();
70 });83 });
71});84});
7285
73describe('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;
90
91 const it_rmrk = (await isUnique() ? it : it.skip);
7792
78 before(async () => {93 before(async () => {
79 await usingApi(async (api, privateKeyWrapper) => {94 await usingApi(async (api, privateKeyWrapper) => {
88 });103 });
89 });104 });
90105
91 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 creation
94109
147 });162 });
148 });163 });
149164
150 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});
208223
209describe('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;
227
228 const it_rmrk = (await isUnique() ? it : it.skip);
212229
213 before(async () => {230 before(async () => {
214 await usingApi(async (api, privateKeyWrapper) => {231 await usingApi(async (api, privateKeyWrapper) => {
220 });237 });
221 });238 });
222239
223 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')