From 7aef819673a2a145ecc7ca44fa534c5f4669f020 Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Tue, 31 Dec 2024 00:08:08 +0800 Subject: [PATCH] Update NFT pallet. --- pallets/nft/src/benchmarking.rs | 18 +- pallets/nft/src/lib.rs | 294 +++++++++++-------- pallets/runtime/develop/src/runtime.rs | 2 +- pallets/runtime/mainnet/src/runtime.rs | 2 +- pallets/runtime/testnet/src/runtime.rs | 2 +- pallets/runtime/tests/src/nft.rs | 82 ++++-- pallets/runtime/tests/src/portfolio.rs | 4 +- pallets/runtime/tests/src/settlement_test.rs | 6 +- pallets/runtime/tests/src/storage.rs | 2 +- primitives/src/asset_metadata.rs | 7 +- primitives/src/nft.rs | 38 ++- 11 files changed, 292 insertions(+), 165 deletions(-) diff --git a/pallets/nft/src/benchmarking.rs b/pallets/nft/src/benchmarking.rs index 71a86b0169..e6602448e7 100644 --- a/pallets/nft/src/benchmarking.rs +++ b/pallets/nft/src/benchmarking.rs @@ -141,8 +141,8 @@ benchmarks! { let collection_keys: NFTCollectionKeys = creates_keys_register_metadata_types::(n); }: _(user.origin, None, nft_type, collection_keys) verify { - assert!(Collection::contains_key(NFTCollectionId(1))); - assert_eq!(CollectionKeys::get(NFTCollectionId(1)).len(), n as usize); + assert!(Collection::::contains_key(NFTCollectionId(1))); + assert_eq!(CollectionKeys::::get(NFTCollectionId(1)).len(), n as usize); } issue_nft { @@ -162,7 +162,7 @@ benchmarks! { verify { for i in 1..n + 1 { assert!( - MetadataValue::contains_key( + MetadataValue::::contains_key( (NFTCollectionId(1), NFTId(1)), AssetMetadataKey::Global(AssetMetadataGlobalKey(i.into())) ) @@ -180,7 +180,7 @@ benchmarks! { verify { for i in 1..n + 1 { assert!( - !MetadataValue::contains_key( + !MetadataValue::::contains_key( (NFTCollectionId(1), NFTId(1)), AssetMetadataKey::Global(AssetMetadataGlobalKey(i.into())) ) @@ -240,17 +240,17 @@ benchmarks! { }) .unwrap(); // Before the controller transfer all NFTs belong to bob - assert_eq!(NumberOfNFTs::get(nfts.asset_id(), bob.did()), n as u64); - assert_eq!(NumberOfNFTs::get(nfts.asset_id(), alice.did()), 0); + assert_eq!(NumberOfNFTs::::get(nfts.asset_id(), bob.did()), n as u64); + assert_eq!(NumberOfNFTs::::get(nfts.asset_id(), alice.did()), 0); }: _(alice.origin.clone(), nfts.clone(), bob_user_portfolio, alice_user_portfolio.kind) verify { - assert_eq!(NumberOfNFTs::get(nfts.asset_id(), bob.did()), 0); - assert_eq!(NumberOfNFTs::get(nfts.asset_id(), alice.did()), n as u64); + assert_eq!(NumberOfNFTs::::get(nfts.asset_id(), bob.did()), 0); + assert_eq!(NumberOfNFTs::::get(nfts.asset_id(), alice.did()), n as u64); for i in 1..n + 1 { assert!(PortfolioNFT::contains_key(alice_user_portfolio, (asset_id, NFTId(i.into())))); assert!(!PortfolioNFT::contains_key(bob_user_portfolio, (asset_id, NFTId(i.into())))); } - assert_eq!(NFTsInCollection::get(nfts.asset_id()), n as u64); + assert_eq!(NFTsInCollection::::get(nfts.asset_id()), n as u64); } } diff --git a/pallets/nft/src/lib.rs b/pallets/nft/src/lib.rs index 1c074a99f9..8d015f91d5 100644 --- a/pallets/nft/src/lib.rs +++ b/pallets/nft/src/lib.rs @@ -4,12 +4,10 @@ use codec::{Decode, Encode}; use frame_support::dispatch::{ DispatchError, DispatchResult, DispatchResultWithPostInfo, PostDispatchInfo, }; -use frame_support::storage::StorageDoubleMap; use frame_support::traits::Get; use frame_support::weights::Weight; -use frame_support::{ - decl_error, decl_event, decl_module, decl_storage, ensure, require_transactional, -}; +use frame_support::{ensure, require_transactional}; +use frame_support::{StorageDoubleMap as _, StorageMap as _}; use sp_std::collections::btree_map::BTreeMap; use sp_std::collections::btree_set::BTreeSet; use sp_std::{vec, vec::Vec}; @@ -31,7 +29,7 @@ use polymesh_primitives::{ type Asset = pallet_asset::Pallet; type ExternalAgents = pallet_external_agents::Pallet; -type Identity = pallet_identity::Pallet; +type IdentityPallet = pallet_identity::Pallet; type Portfolio = pallet_portfolio::Pallet; #[cfg(feature = "runtime-benchmarks")] @@ -47,22 +45,36 @@ pub trait WeightInfo { fn controller_transfer(n: u32) -> Weight; } -pub trait Config: - frame_system::Config + pallet_asset::Config + pallet_identity::Config + pallet_portfolio::Config -{ - type RuntimeEvent: From + Into<::RuntimeEvent>; - - type WeightInfo: WeightInfo; - - type Compliance: ComplianceFnConfig; - - type MaxNumberOfCollectionKeys: Get; +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::{OptionQuery, *}; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: + frame_system::Config + + pallet_asset::Config + + pallet_identity::Config + + pallet_portfolio::Config + { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type WeightInfo: WeightInfo; + type Compliance: ComplianceFnConfig; + #[pallet::constant] + type MaxNumberOfCollectionKeys: Get; + #[pallet::constant] + type MaxNumberOfNFTsCount: Get; + } - type MaxNumberOfNFTsCount: Get; -} + #[pallet::pallet] + pub struct Pallet(_); -decl_event!( - pub enum Event { + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { /// Emitted when a new nft collection is created. NftCollectionCreated(IdentityId, AssetId, NFTCollectionId), /// Emitted when NFTs were issued, redeemed or transferred. @@ -76,58 +88,100 @@ decl_event!( PortfolioUpdateReason, ), } -); - -decl_storage!( - trait Store for Pallet as NFT { - /// The total number of NFTs per identity. - pub NumberOfNFTs get(fn balance_of): double_map hasher(blake2_128_concat) AssetId, hasher(identity) IdentityId => NFTCount; - - /// The collection id corresponding to each asset. - pub CollectionAsset get(fn collection_asset): map hasher(blake2_128_concat) AssetId => NFTCollectionId; - - /// All collection details for a given collection id. - pub Collection get(fn nft_collection): map hasher(blake2_128_concat) NFTCollectionId => NFTCollection; - - /// All mandatory metadata keys for a given collection. - pub CollectionKeys get(fn collection_keys): map hasher(blake2_128_concat) NFTCollectionId => BTreeSet; - - /// The metadata value of an nft given its collection id, token id and metadata key. - pub MetadataValue get(fn metadata_value): - double_map hasher(blake2_128_concat) (NFTCollectionId, NFTId), hasher(blake2_128_concat) AssetMetadataKey => AssetMetadataValue; - - /// The total number of NFTs in a collection - pub NFTsInCollection get(fn nfts_in_collection): map hasher(blake2_128_concat) AssetId => NFTCount; - - /// Tracks the owner of an NFT - pub NFTOwner get(fn nft_owner): double_map hasher(blake2_128_concat) AssetId, hasher(blake2_128_concat) NFTId => Option; - - /// The last `NFTId` used for an NFT. - pub CurrentNFTId get(fn current_nft_id): map hasher(blake2_128_concat) NFTCollectionId => Option; - /// The last `NFTCollectionId` used for a collection. - pub CurrentCollectionId get(fn current_collection_id): Option; - - /// Storage version. - StorageVersion get(fn storage_version) build(|_| Version::new(4)): Version; + /// The total number of NFTs per identity. + #[pallet::storage] + #[pallet::getter(fn number_of_nfts)] + pub type NumberOfNFTs = + StorageDoubleMap<_, Blake2_128Concat, AssetId, Identity, IdentityId, NFTCount, ValueQuery>; + + /// The collection id corresponding to each asset. + #[pallet::storage] + #[pallet::getter(fn collection_asset)] + pub type CollectionAsset = + StorageMap<_, Blake2_128Concat, AssetId, NFTCollectionId, ValueQuery>; + + /// All collection details for a given collection id. + #[pallet::storage] + #[pallet::getter(fn collection)] + pub type Collection = + StorageMap<_, Blake2_128Concat, NFTCollectionId, NFTCollection, ValueQuery>; + + /// All mandatory metadata keys for a given collection. + #[pallet::storage] + #[pallet::unbounded] + #[pallet::getter(fn collection_keys)] + pub type CollectionKeys = + StorageMap<_, Blake2_128Concat, NFTCollectionId, BTreeSet, ValueQuery>; + + /// The metadata value of an nft given its collection id, token id and metadata key. + #[pallet::storage] + #[pallet::unbounded] + #[pallet::getter(fn metadata_value)] + pub type MetadataValue = StorageDoubleMap< + _, + Blake2_128Concat, + (NFTCollectionId, NFTId), + Blake2_128Concat, + AssetMetadataKey, + AssetMetadataValue, + ValueQuery, + >; + + /// The total number of NFTs in a collection. + #[pallet::storage] + #[pallet::getter(fn nfts_in_collection)] + pub type NFTsInCollection = + StorageMap<_, Blake2_128Concat, AssetId, NFTCount, ValueQuery>; + + /// Tracks the owner of an NFT + #[pallet::storage] + #[pallet::getter(fn nft_owner)] + pub type NFTOwner = StorageDoubleMap< + _, + Blake2_128Concat, + AssetId, + Blake2_128Concat, + NFTId, + PortfolioId, + OptionQuery, + >; + + /// The last `NFTId` used for an NFT. + #[pallet::storage] + #[pallet::getter(fn current_nft_id)] + pub type CurrentNFTId = + StorageMap<_, Blake2_128Concat, NFTCollectionId, NFTId, OptionQuery>; + + /// The last `NFTCollectionId` used for a collection. + #[pallet::storage] + #[pallet::getter(fn current_collection_id)] + pub type CurrentCollectionId = StorageValue<_, NFTCollectionId, OptionQuery>; + + /// Storage version. + #[pallet::storage] + pub(super) type StorageVersion = StorageValue<_, Version, ValueQuery>; + + #[pallet::genesis_config] + #[derive(Default)] + pub struct GenesisConfig; + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + StorageVersion::::put(Version::new(4)); + } } -); - -decl_module! { - pub struct Module for enum Call where origin: T::RuntimeOrigin { - - type Error = Error; - - const MaxNumberOfCollectionKeys: u8 = T::MaxNumberOfCollectionKeys::get(); - const MaxNumberOfNFTsCount: u32 = T::MaxNumberOfNFTsCount::get(); - - /// Initializes the default event for this module. - fn deposit_event() = default; + #[pallet::hooks] + impl Hooks> for Pallet { fn on_runtime_upgrade() -> Weight { Weight::zero() } + } + #[pallet::call] + impl Pallet { /// Cretes a new `NFTCollection`. /// /// # Arguments @@ -145,12 +199,13 @@ decl_module! { /// /// # Permissions /// * Asset - #[weight = ::WeightInfo::create_nft_collection(collection_keys.len() as u32)] + #[pallet::weight(::WeightInfo::create_nft_collection(collection_keys.len() as u32))] + #[pallet::call_index(0)] pub fn create_nft_collection( - origin, + origin: OriginFor, asset_id: Option, nft_type: Option, - collection_keys: NFTCollectionKeys + collection_keys: NFTCollectionKeys, ) -> DispatchResult { Self::base_create_nft_collection(origin, asset_id, nft_type, collection_keys) } @@ -172,8 +227,14 @@ decl_module! { /// # Permissions /// * Asset /// * Portfolio - #[weight = ::WeightInfo::issue_nft(nft_metadata_attributes.len() as u32)] - pub fn issue_nft(origin, asset_id: AssetId, nft_metadata_attributes: Vec, portfolio_kind: PortfolioKind) -> DispatchResult { + #[pallet::weight(::WeightInfo::issue_nft(nft_metadata_attributes.len() as u32))] + #[pallet::call_index(1)] + pub fn issue_nft( + origin: OriginFor, + asset_id: AssetId, + nft_metadata_attributes: Vec, + portfolio_kind: PortfolioKind, + ) -> DispatchResult { Self::base_issue_nft(origin, asset_id, nft_metadata_attributes, portfolio_kind) } @@ -192,18 +253,19 @@ decl_module! { /// # Permissions /// * Asset /// * Portfolio - #[weight = ::WeightInfo::redeem_nft( + #[pallet::weight(::WeightInfo::redeem_nft( number_of_keys.map_or( u32::from(T::MaxNumberOfCollectionKeys::get()), |v| u32::from(v) ) - )] + ))] + #[pallet::call_index(2)] pub fn redeem_nft( - origin, + origin: OriginFor, asset_id: AssetId, nft_id: NFTId, portfolio_kind: PortfolioKind, - number_of_keys: Option + number_of_keys: Option, ) -> DispatchResultWithPostInfo { Self::base_redeem_nft(origin, asset_id, nft_id, portfolio_kind, number_of_keys) } @@ -219,20 +281,20 @@ decl_module! { /// # Permissions /// * Asset /// * Portfolio - #[weight = ::WeightInfo::controller_transfer(nfts.len() as u32)] + #[pallet::weight(::WeightInfo::controller_transfer(nfts.len() as u32))] + #[pallet::call_index(3)] pub fn controller_transfer( - origin, + origin: OriginFor, nfts: NFTs, source_portfolio: PortfolioId, - callers_portfolio_kind: PortfolioKind + callers_portfolio_kind: PortfolioKind, ) -> DispatchResult { Self::base_controller_transfer(origin, nfts, source_portfolio, callers_portfolio_kind) } } -} -decl_error! { - pub enum Error for Pallet { + #[pallet::error] + pub enum Error { /// An overflow while calculating the balance. BalanceOverflow, /// An underflow while calculating the balance. @@ -318,7 +380,7 @@ impl Pallet { }, None => { let caller_data = - Identity::::ensure_origin_call_permissions(origin.clone())?; + IdentityPallet::::ensure_origin_call_permissions(origin.clone())?; let asset_id = Asset::::generate_asset_id(caller_data.sender, false); (true, caller_data.primary_did, asset_id) } @@ -327,7 +389,7 @@ impl Pallet { // Verifies if the asset_id is already associated to an NFT collection ensure!( - !CollectionAsset::contains_key(&asset_id), + !CollectionAsset::::contains_key(&asset_id), Error::::CollectionAlredyRegistered ); @@ -369,9 +431,9 @@ impl Pallet { // Creates the nft collection let collection_id = Self::update_current_collection_id()?; let nft_collection = NFTCollection::new(collection_id, asset_id.clone()); - Collection::insert(&collection_id, nft_collection); - CollectionKeys::insert(&collection_id, collection_keys); - CollectionAsset::insert(&asset_id, &collection_id); + Collection::::insert(&collection_id, nft_collection); + CollectionKeys::::insert(&collection_id, collection_keys); + CollectionAsset::::insert(&asset_id, &collection_id); Self::deposit_event(Event::NftCollectionCreated( caller_did, @@ -389,7 +451,7 @@ impl Pallet { ) -> DispatchResult { // Verifies if the collection exists let collection_id = - CollectionAsset::try_get(&asset_id).map_err(|_| Error::::CollectionNotFound)?; + CollectionAsset::::try_get(&asset_id).map_err(|_| Error::::CollectionNotFound)?; // Verifies if the caller has the right permissions (regarding asset and portfolio) let caller_portfolio = Asset::::ensure_origin_asset_and_portfolio_permissions( @@ -426,20 +488,20 @@ impl Pallet { } // Mints the NFT and adds it to the caller's portfolio - let new_supply = NFTsInCollection::get(&asset_id) + let new_supply = NFTsInCollection::::get(&asset_id) .checked_add(1) .ok_or(Error::::SupplyOverflow)?; - let new_balance = NumberOfNFTs::get(&asset_id, &caller_portfolio.did) + let new_balance = NumberOfNFTs::::get(&asset_id, &caller_portfolio.did) .checked_add(1) .ok_or(Error::::BalanceOverflow)?; let nft_id = Self::update_current_nft_id(&collection_id)?; - NFTsInCollection::insert(&asset_id, new_supply); - NumberOfNFTs::insert(&asset_id, &caller_portfolio.did, new_balance); + NFTsInCollection::::insert(&asset_id, new_supply); + NumberOfNFTs::::insert(&asset_id, &caller_portfolio.did, new_balance); for (metadata_key, metadata_value) in nft_attributes.into_iter() { - MetadataValue::insert((&collection_id, &nft_id), metadata_key, metadata_value); + MetadataValue::::insert((&collection_id, &nft_id), metadata_key, metadata_value); } PortfolioNFT::insert(caller_portfolio, (asset_id, nft_id), true); - NFTOwner::insert(asset_id, nft_id, caller_portfolio); + NFTOwner::::insert(asset_id, nft_id, caller_portfolio); Self::deposit_event(Event::NFTPortfolioUpdated( caller_portfolio.did, @@ -462,7 +524,7 @@ impl Pallet { ) -> DispatchResultWithPostInfo { // Verifies if the collection exists let collection_id = - CollectionAsset::try_get(&asset_id).map_err(|_| Error::::CollectionNotFound)?; + CollectionAsset::::try_get(&asset_id).map_err(|_| Error::::CollectionNotFound)?; // Ensure origin is agent with custody and permissions for portfolio. let caller_portfolio = Asset::::ensure_origin_asset_and_portfolio_permissions( @@ -483,17 +545,17 @@ impl Pallet { ); // Burns the NFT - let new_supply = NFTsInCollection::get(&asset_id) + let new_supply = NFTsInCollection::::get(&asset_id) .checked_sub(1) .ok_or(Error::::SupplyUnderflow)?; - let new_balance = NumberOfNFTs::get(&asset_id, &caller_portfolio.did) + let new_balance = NumberOfNFTs::::get(&asset_id, &caller_portfolio.did) .checked_sub(1) .ok_or(Error::::BalanceUnderflow)?; - NFTsInCollection::insert(&asset_id, new_supply); - NumberOfNFTs::insert(&asset_id, &caller_portfolio.did, new_balance); + NFTsInCollection::::insert(&asset_id, new_supply); + NumberOfNFTs::::insert(&asset_id, &caller_portfolio.did, new_balance); PortfolioNFT::remove(&caller_portfolio, (&asset_id, &nft_id)); - NFTOwner::remove(asset_id, nft_id); - let removed_keys = MetadataValue::drain_prefix((&collection_id, &nft_id)).count(); + NFTOwner::::remove(asset_id, nft_id); + let removed_keys = MetadataValue::::drain_prefix((&collection_id, &nft_id)).count(); if let Some(number_of_keys) = number_of_keys { ensure!( usize::from(number_of_keys) >= removed_keys, @@ -558,7 +620,7 @@ impl Pallet { weight_meter: Option<&mut WeightMeter>, ) -> DispatchResult { // Verifies if there is a collection associated to the NFTs - if !CollectionAsset::contains_key(nfts.asset_id()) { + if !CollectionAsset::::contains_key(nfts.asset_id()) { return Err(Error::::InvalidNFTTransferCollectionNotFound.into()); } @@ -571,7 +633,7 @@ impl Pallet { // Verifies that the sender has the required nft count let nfts_transferred = nfts.len() as u64; ensure!( - NumberOfNFTs::get(nfts.asset_id(), sender_portfolio.did) >= nfts_transferred, + NumberOfNFTs::::get(nfts.asset_id(), sender_portfolio.did) >= nfts_transferred, Error::::InvalidNFTTransferInsufficientCount ); @@ -583,7 +645,7 @@ impl Pallet { Self::ensure_nft_ownership(sender_portfolio, nfts)?; // Verfies that the receiver will not overflow - NumberOfNFTs::get(nfts.asset_id(), receiver_portfolio.did) + NumberOfNFTs::::get(nfts.asset_id(), receiver_portfolio.did) .checked_add(nfts_transferred) .ok_or(Error::::InvalidNFTTransferCountOverflow)?; @@ -600,13 +662,13 @@ impl Pallet { // Verifies if the receiver has a valid CDD claim. ensure!( - Identity::::has_valid_cdd(receiver_portfolio.did), + IdentityPallet::::has_valid_cdd(receiver_portfolio.did), Error::::InvalidNFTTransferInvalidReceiverCDD ); // Verifies if the sender has a valid CDD claim. ensure!( - Identity::::has_valid_cdd(sender_portfolio.did), + IdentityPallet::::has_valid_cdd(sender_portfolio.did), Error::::InvalidNFTTransferInvalidSenderCDD ); @@ -665,17 +727,17 @@ impl Pallet { ) { // Update the balance of the sender and the receiver let transferred_amount = nfts.len() as u64; - NumberOfNFTs::mutate(nfts.asset_id(), sender_portfolio.did, |balance| { + NumberOfNFTs::::mutate(nfts.asset_id(), sender_portfolio.did, |balance| { *balance -= transferred_amount }); - NumberOfNFTs::mutate(nfts.asset_id(), receiver_portfolio.did, |balance| { + NumberOfNFTs::::mutate(nfts.asset_id(), receiver_portfolio.did, |balance| { *balance += transferred_amount }); // Update the portfolio of the sender and the receiver for nft_id in nfts.ids() { PortfolioNFT::remove(sender_portfolio, (nfts.asset_id(), nft_id)); PortfolioNFT::insert(receiver_portfolio, (nfts.asset_id(), nft_id), true); - NFTOwner::insert(nfts.asset_id(), nft_id, receiver_portfolio); + NFTOwner::::insert(nfts.asset_id(), nft_id, receiver_portfolio); } } @@ -719,7 +781,7 @@ impl Pallet { let mut nft_transfer_errors = Vec::new(); // If the collection doesn't exist, there's no point in assessing anything else - if !CollectionAsset::contains_key(nfts.asset_id()) { + if !CollectionAsset::::contains_key(nfts.asset_id()) { return vec![Error::::InvalidNFTTransferCollectionNotFound.into()]; } @@ -733,7 +795,7 @@ impl Pallet { } let nfts_transferred = nfts.len() as u64; - if NumberOfNFTs::get(nfts.asset_id(), &sender_portfolio.did) < nfts_transferred { + if NumberOfNFTs::::get(nfts.asset_id(), &sender_portfolio.did) < nfts_transferred { nft_transfer_errors.push(Error::::InvalidNFTTransferInsufficientCount.into()); } @@ -758,15 +820,15 @@ impl Pallet { } } - if !Identity::::has_valid_cdd(receiver_portfolio.did) { + if !IdentityPallet::::has_valid_cdd(receiver_portfolio.did) { nft_transfer_errors.push(Error::::InvalidNFTTransferInvalidReceiverCDD.into()); } - if !Identity::::has_valid_cdd(sender_portfolio.did) { + if !IdentityPallet::::has_valid_cdd(sender_portfolio.did) { nft_transfer_errors.push(Error::::InvalidNFTTransferInvalidSenderCDD.into()); } - if NumberOfNFTs::get(nfts.asset_id(), &receiver_portfolio.did) + if NumberOfNFTs::::get(nfts.asset_id(), &receiver_portfolio.did) .checked_add(nfts_transferred) .is_none() { @@ -795,7 +857,7 @@ impl Pallet { /// Adds one to `CurrentCollectionId`. fn update_current_collection_id() -> Result { - CurrentCollectionId::try_mutate(|current_collection_id| match current_collection_id { + CurrentCollectionId::::try_mutate(|current_collection_id| match current_collection_id { Some(current_id) => { let new_id = try_next_pre::(current_id)?; *current_collection_id = Some(new_id); @@ -811,7 +873,7 @@ impl Pallet { /// Adds one to the `NFTId` that belongs to `collection_id`. fn update_current_nft_id(collection_id: &NFTCollectionId) -> Result { - CurrentNFTId::try_mutate(collection_id, |current_nft_id| match current_nft_id { + CurrentNFTId::::try_mutate(collection_id, |current_nft_id| match current_nft_id { Some(current_id) => { let new_nft_id = try_next_pre::(current_id)?; *current_nft_id = Some(new_nft_id); @@ -828,9 +890,9 @@ impl Pallet { impl NFTTrait for Pallet { fn is_collection_key(asset_id: &AssetId, metadata_key: &AssetMetadataKey) -> bool { - match CollectionAsset::try_get(asset_id) { + match CollectionAsset::::try_get(asset_id) { Ok(collection_id) => { - let key_set = CollectionKeys::get(&collection_id); + let key_set = CollectionKeys::::get(&collection_id); key_set.contains(metadata_key) } Err(_) => false, @@ -838,7 +900,7 @@ impl NFTTrait for Pallet { } fn move_portfolio_owner(asset_id: AssetId, nft_id: NFTId, new_owner_portfolio: PortfolioId) { - NFTOwner::insert(asset_id, nft_id, new_owner_portfolio); + NFTOwner::::insert(asset_id, nft_id, new_owner_portfolio); } #[cfg(feature = "runtime-benchmarks")] diff --git a/pallets/runtime/develop/src/runtime.rs b/pallets/runtime/develop/src/runtime.rs index 81d504a269..852ed2e47f 100644 --- a/pallets/runtime/develop/src/runtime.rs +++ b/pallets/runtime/develop/src/runtime.rs @@ -428,7 +428,7 @@ construct_runtime!( // Preimage register. Used by `pallet_scheduler`. Preimage: pallet_preimage::{Pallet, Call, Storage, Event} = 48, - Nft: pallet_nft::{Pallet, Call, Storage, Event} = 49, + Nft: pallet_nft::{Pallet, Call, Storage, Event} = 49, ElectionProviderMultiPhase: pallet_election_provider_multi_phase::{Pallet, Call, Storage, Event, ValidateUnsigned} = 50, } diff --git a/pallets/runtime/mainnet/src/runtime.rs b/pallets/runtime/mainnet/src/runtime.rs index fa04f4e435..9431c80de5 100644 --- a/pallets/runtime/mainnet/src/runtime.rs +++ b/pallets/runtime/mainnet/src/runtime.rs @@ -378,7 +378,7 @@ construct_runtime!( // Preimage register. Used by `pallet_scheduler`. Preimage: pallet_preimage::{Pallet, Call, Storage, Event} = 48, - Nft: pallet_nft::{Pallet, Call, Storage, Event} = 49, + Nft: pallet_nft::{Pallet, Call, Storage, Event} = 49, ElectionProviderMultiPhase: pallet_election_provider_multi_phase::{Pallet, Call, Storage, Event, ValidateUnsigned} = 50, } diff --git a/pallets/runtime/testnet/src/runtime.rs b/pallets/runtime/testnet/src/runtime.rs index eba9d6a857..8a6002065c 100644 --- a/pallets/runtime/testnet/src/runtime.rs +++ b/pallets/runtime/testnet/src/runtime.rs @@ -384,7 +384,7 @@ construct_runtime!( // Preimage register. Used by `pallet_scheduler`. Preimage: pallet_preimage::{Pallet, Call, Storage, Event} = 48, - Nft: pallet_nft::{Pallet, Call, Storage, Event} = 49, + Nft: pallet_nft::{Pallet, Call, Storage, Event} = 49, ElectionProviderMultiPhase: pallet_election_provider_multi_phase::{Pallet, Call, Storage, Event, ValidateUnsigned} = 50, } diff --git a/pallets/runtime/tests/src/nft.rs b/pallets/runtime/tests/src/nft.rs index 3fce1d5908..dee33de0d5 100644 --- a/pallets/runtime/tests/src/nft.rs +++ b/pallets/runtime/tests/src/nft.rs @@ -1,6 +1,5 @@ use chrono::prelude::Utc; -use frame_support::storage::StorageValue; -use frame_support::{assert_noop, assert_ok, StorageDoubleMap, StorageMap}; +use frame_support::{assert_noop, assert_ok, StorageDoubleMap}; use pallet_nft::Event; use pallet_nft::{ @@ -207,9 +206,15 @@ pub(crate) fn create_nft_collection( None, collection_keys )); - assert!(Collection::contains_key(NFTCollectionId(1))); - assert_eq!(CollectionKeys::get(NFTCollectionId(1)).len(), n_keys); - assert_eq!(CurrentCollectionId::get(), Some(NFTCollectionId(1))); + assert!(Collection::::contains_key(NFTCollectionId(1))); + assert_eq!( + CollectionKeys::::get(NFTCollectionId(1)).len(), + n_keys + ); + assert_eq!( + CurrentCollectionId::::get(), + Some(NFTCollectionId(1)) + ); asset_id } @@ -404,14 +409,14 @@ fn mint_nft_successfully() { PortfolioKind::Default )); assert_eq!( - MetadataValue::get( + MetadataValue::::get( (NFTCollectionId(1), NFTId(1)), AssetMetadataKey::Local(AssetMetadataLocalKey(1)) ), AssetMetadataValue(b"test".to_vec()) ); - assert_eq!(NumberOfNFTs::get(&asset_id, alice.did), 1); - assert_eq!(NFTsInCollection::get(&asset_id), 1); + assert_eq!(NumberOfNFTs::::get(&asset_id, alice.did), 1); + assert_eq!(NFTsInCollection::::get(&asset_id), 1); assert_eq!( PortfolioNFT::get( PortfolioId::default_portfolio(alice.did), @@ -420,10 +425,13 @@ fn mint_nft_successfully() { true ); assert_eq!( - NFTOwner::get(asset_id, NFTId(1)), + NFTOwner::::get(asset_id, NFTId(1)), Some(alice_default_portfolio) ); - assert_eq!(CurrentNFTId::get(NFTCollectionId(1)), Some(NFTId(1))); + assert_eq!( + CurrentNFTId::::get(NFTCollectionId(1)), + Some(NFTId(1)) + ); }); } @@ -579,19 +587,25 @@ fn burn_nft() { PortfolioKind::Default, None )); - assert!(!MetadataValue::contains_key( + assert!(!MetadataValue::::contains_key( (NFTCollectionId(1), NFTId(1)), AssetMetadataKey::Local(AssetMetadataLocalKey(1)) ),); - assert_eq!(NumberOfNFTs::get(&asset_id, alice.did), 0); - assert_eq!(NFTsInCollection::get(&asset_id), 0); + assert_eq!(NumberOfNFTs::::get(&asset_id, alice.did), 0); + assert_eq!(NFTsInCollection::::get(&asset_id), 0); assert!(!PortfolioNFT::contains_key( PortfolioId::default_portfolio(alice.did), (&asset_id, NFTId(1)) ),); - assert_eq!(NFTOwner::get(asset_id, NFTId(1)), None); - assert_eq!(CurrentNFTId::get(NFTCollectionId(1)), Some(NFTId(1))); - assert_eq!(CurrentCollectionId::get(), Some(NFTCollectionId(1))); + assert_eq!(NFTOwner::::get(asset_id, NFTId(1)), None); + assert_eq!( + CurrentNFTId::::get(NFTCollectionId(1)), + Some(NFTId(1)) + ); + assert_eq!( + CurrentCollectionId::::get(), + Some(NFTCollectionId(1)) + ); }); } @@ -914,7 +928,7 @@ fn transfer_nft() { &mut weight_meter, ) })); - assert_eq!(NumberOfNFTs::get(&asset_id, alice.did), 0); + assert_eq!(NumberOfNFTs::::get(&asset_id, alice.did), 0); assert_eq!( PortfolioNFT::get( PortfolioId::default_portfolio(alice.did), @@ -922,8 +936,8 @@ fn transfer_nft() { ), false ); - assert_eq!(NumberOfNFTs::get(&asset_id, bob.did), 1); - assert_eq!(NFTsInCollection::get(&asset_id), 1); + assert_eq!(NumberOfNFTs::::get(&asset_id, bob.did), 1); + assert_eq!(NFTsInCollection::::get(&asset_id), 1); assert_eq!( PortfolioNFT::get( PortfolioId::default_portfolio(bob.did), @@ -931,7 +945,10 @@ fn transfer_nft() { ), true ); - assert_eq!(NFTOwner::get(asset_id, NFTId(1)), Some(receiver_portfolio)); + assert_eq!( + NFTOwner::::get(asset_id, NFTId(1)), + Some(receiver_portfolio) + ); assert_eq!( super::storage::EventTest::Nft(Event::NFTPortfolioUpdated( IdentityId::default(), @@ -995,12 +1012,18 @@ fn controller_transfer() { ) })); // Before the controller transfer all NFTs belong to bob - assert_eq!(NumberOfNFTs::get(nfts.asset_id(), bob.did), 1); + assert_eq!( + NumberOfNFTs::::get(nfts.asset_id(), bob.did), + 1 + ); assert!(PortfolioNFT::contains_key( bob_portfolio, (asset_id, NFTId(1)) )); - assert_eq!(NumberOfNFTs::get(nfts.asset_id(), alice.did), 0); + assert_eq!( + NumberOfNFTs::::get(nfts.asset_id(), alice.did), + 0 + ); assert!(!PortfolioNFT::contains_key( alice_portfolio, (asset_id, NFTId(1)) @@ -1012,17 +1035,26 @@ fn controller_transfer() { bob_portfolio, alice_portfolio.kind )); - assert_eq!(NumberOfNFTs::get(nfts.asset_id(), bob.did), 0); + assert_eq!( + NumberOfNFTs::::get(nfts.asset_id(), bob.did), + 0 + ); assert!(!PortfolioNFT::contains_key( bob_portfolio, (asset_id, NFTId(1)) )); - assert_eq!(NumberOfNFTs::get(nfts.asset_id(), alice.did), 1); + assert_eq!( + NumberOfNFTs::::get(nfts.asset_id(), alice.did), + 1 + ); assert!(PortfolioNFT::contains_key( alice_portfolio, (asset_id, NFTId(1)) )); - assert_eq!(NFTOwner::get(asset_id, NFTId(1)), Some(alice_portfolio)); + assert_eq!( + NFTOwner::::get(asset_id, NFTId(1)), + Some(alice_portfolio) + ); assert_eq!( super::storage::EventTest::Nft(Event::NFTPortfolioUpdated( alice.did, diff --git a/pallets/runtime/tests/src/portfolio.rs b/pallets/runtime/tests/src/portfolio.rs index 5001b29b0a..34421792fe 100644 --- a/pallets/runtime/tests/src/portfolio.rs +++ b/pallets/runtime/tests/src/portfolio.rs @@ -821,11 +821,11 @@ fn move_portfolio_nfts() { true ); assert_eq!( - NFTOwner::get(asset_id, NFTId(1)), + NFTOwner::::get(asset_id, NFTId(1)), Some(alice_custom_portfolio) ); assert_eq!( - NFTOwner::get(asset_id, NFTId(2)), + NFTOwner::::get(asset_id, NFTId(2)), Some(alice_custom_portfolio) ); }); diff --git a/pallets/runtime/tests/src/settlement_test.rs b/pallets/runtime/tests/src/settlement_test.rs index 4b0143bd1d..666bba25e0 100644 --- a/pallets/runtime/tests/src/settlement_test.rs +++ b/pallets/runtime/tests/src/settlement_test.rs @@ -2709,7 +2709,7 @@ fn add_and_affirm_nft_instruction() { )); // Before bob accepts the transaction balances must not be changed and the NFT must be locked. - assert_eq!(NumberOfNFTs::get(asset_id, alice.did), 1); + assert_eq!(NumberOfNFTs::::get(asset_id, alice.did), 1); assert_eq!( PortfolioNFT::get( PortfolioId::default_portfolio(alice.did), @@ -2732,8 +2732,8 @@ fn add_and_affirm_nft_instruction() { default_portfolio_btreeset(bob.did), )); next_block(); - assert_eq!(NumberOfNFTs::get(asset_id, alice.did), 0); - assert_eq!(NumberOfNFTs::get(asset_id, bob.did), 1); + assert_eq!(NumberOfNFTs::::get(asset_id, alice.did), 0); + assert_eq!(NumberOfNFTs::::get(asset_id, bob.did), 1); assert_eq!( PortfolioNFT::get( PortfolioId::default_portfolio(alice.did), diff --git a/pallets/runtime/tests/src/storage.rs b/pallets/runtime/tests/src/storage.rs index a874673fc4..d4099b6e2c 100644 --- a/pallets/runtime/tests/src/storage.rs +++ b/pallets/runtime/tests/src/storage.rs @@ -327,7 +327,7 @@ frame_support::construct_runtime!( // Preimage register. Used by `pallet_scheduler`. Preimage: pallet_preimage::{Pallet, Call, Storage, Event} = 48, - Nft: pallet_nft::{Pallet, Call, Storage, Event} = 49, + Nft: pallet_nft::{Pallet, Call, Storage, Event} = 49, // Testing only. Example: example::{Pallet, Call} = 201, diff --git a/primitives/src/asset_metadata.rs b/primitives/src/asset_metadata.rs index fa24d97aa5..aac2b800a3 100644 --- a/primitives/src/asset_metadata.rs +++ b/primitives/src/asset_metadata.rs @@ -15,6 +15,7 @@ use crate::impl_checked_inc; use crate::Url; +use codec::MaxEncodedLen; use codec::{Decode, DecodeAll, Encode}; use polymesh_primitives_derive::VecU8StrongTyped; use scale_info::{PortableRegistry, TypeInfo}; @@ -29,19 +30,19 @@ use sp_std::prelude::Vec; pub struct AssetMetadataName(#[cfg_attr(feature = "std", serde(with = "serde_bytes"))] pub Vec); /// Asset Metadata Global Key. -#[derive(Encode, Decode, TypeInfo)] +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo)] #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, Ord, PartialOrd)] pub struct AssetMetadataGlobalKey(pub u64); impl_checked_inc!(AssetMetadataGlobalKey); /// Asset Metadata Local Key. -#[derive(Encode, Decode, TypeInfo)] +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo)] #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, Ord, PartialOrd)] pub struct AssetMetadataLocalKey(pub u64); impl_checked_inc!(AssetMetadataLocalKey); /// Asset Metadata Key. -#[derive(Encode, Decode, TypeInfo)] +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo)] #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] pub enum AssetMetadataKey { /// Global Metadata Key. diff --git a/primitives/src/nft.rs b/primitives/src/nft.rs index dd720c5c25..42512a0217 100644 --- a/primitives/src/nft.rs +++ b/primitives/src/nft.rs @@ -1,3 +1,4 @@ +use codec::MaxEncodedLen; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; @@ -15,20 +16,51 @@ use crate::impl_checked_inc; pub type NFTCount = u64; /// Controls the next available id for an NFT collection. -#[derive(Clone, Copy, Debug, Decode, Default, Eq, Encode, PartialEq, TypeInfo)] +#[derive( + Clone, + Copy, + Debug, + Decode, + MaxEncodedLen, + Default, + Eq, + Encode, + PartialEq, + TypeInfo +)] pub struct NFTCollectionId(pub u64); impl_checked_inc!(NFTCollectionId); /// Controls the next available id for an NFT within a collection. #[derive( - Clone, Copy, Debug, Decode, Default, Encode, Eq, Ord, PartialOrd, PartialEq, TypeInfo + Clone, + Copy, + Debug, + Decode, + Default, + Encode, + MaxEncodedLen, + Eq, + Ord, + PartialOrd, + PartialEq, + TypeInfo )] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct NFTId(pub u64); impl_checked_inc!(NFTId); /// Defines an NFT collection. -#[derive(Clone, Debug, Decode, Default, Encode, PartialEq, TypeInfo)] +#[derive( + Clone, + Debug, + Decode, + Default, + Encode, + MaxEncodedLen, + PartialEq, + TypeInfo +)] pub struct NFTCollection { id: NFTCollectionId, asset_id: AssetId,