diff --git a/nft/src/lib.rs b/nft/src/lib.rs index 16cff62ff..0387e2618 100644 --- a/nft/src/lib.rs +++ b/nft/src/lib.rs @@ -22,21 +22,26 @@ #![allow(clippy::unused_unit)] use codec::{Decode, Encode}; -use frame_support::{ensure, pallet_prelude::*, Parameter}; +use frame_support::{ + ensure, + pallet_prelude::*, + traits::{Get, MaxEncodedLen}, + BoundedVec, Parameter, +}; use sp_runtime::{ traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedSub, MaybeSerializeDeserialize, Member, One, Zero}, ArithmeticError, DispatchError, DispatchResult, RuntimeDebug, }; -use sp_std::vec::Vec; +use sp_std::{convert::TryInto, vec::Vec}; mod mock; mod tests; /// Class info -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug)] -pub struct ClassInfo { +#[derive(Encode, Decode, Clone, Eq, PartialEq, MaxEncodedLen, RuntimeDebug)] +pub struct ClassInfo { /// Class metadata - pub metadata: Vec, + pub metadata: ClassMetadataOf, /// Total issuance for the class pub total_issuance: TokenId, /// Class owner @@ -46,10 +51,10 @@ pub struct ClassInfo { } /// Token info -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug)] -pub struct TokenInfo { +#[derive(Encode, Decode, Clone, Eq, PartialEq, MaxEncodedLen, RuntimeDebug)] +pub struct TokenInfo { /// Token metadata - pub metadata: Vec, + pub metadata: TokenMetadataOf, /// Token owner pub owner: AccountId, /// Token Properties @@ -72,11 +77,22 @@ pub mod module { type ClassData: Parameter + Member + MaybeSerializeDeserialize; /// The token properties type type TokenData: Parameter + Member + MaybeSerializeDeserialize; + /// The maximum size of a class's metadata + type MaxClassMetadata: Get; + /// The maximum size of a token's metadata + type MaxTokenMetadata: Get; } - pub type ClassInfoOf = - ClassInfo<::TokenId, ::AccountId, ::ClassData>; - pub type TokenInfoOf = TokenInfo<::AccountId, ::TokenData>; + pub type ClassMetadataOf = BoundedVec::MaxClassMetadata>; + pub type TokenMetadataOf = BoundedVec::MaxTokenMetadata>; + pub type ClassInfoOf = ClassInfo< + ::TokenId, + ::AccountId, + ::ClassData, + ClassMetadataOf, + >; + pub type TokenInfoOf = + TokenInfo<::AccountId, ::TokenData, TokenMetadataOf>; pub type GenesisTokenData = ( ::AccountId, // Token owner @@ -106,6 +122,8 @@ pub mod module { /// Can not destroy class /// Total issuance is not 0 CannotDestroyClass, + /// Failed because the Maximum amount of metadata was exceeded + MaxMetadataExceeded, } /// Next available class ID. @@ -182,6 +200,9 @@ impl Pallet { metadata: Vec, data: T::ClassData, ) -> Result { + let bounded_metadata: BoundedVec = + metadata.try_into().map_err(|_| Error::::MaxMetadataExceeded)?; + let class_id = NextClassId::::try_mutate(|id| -> Result { let current_id = *id; *id = id.checked_add(&One::one()).ok_or(Error::::NoAvailableClassId)?; @@ -189,7 +210,7 @@ impl Pallet { })?; let info = ClassInfo { - metadata, + metadata: bounded_metadata, total_issuance: Default::default(), owner: owner.clone(), data, @@ -226,6 +247,9 @@ impl Pallet { data: T::TokenData, ) -> Result { NextTokenId::::try_mutate(class_id, |id| -> Result { + let bounded_metadata: BoundedVec = + metadata.try_into().map_err(|_| Error::::MaxMetadataExceeded)?; + let token_id = *id; *id = id.checked_add(&One::one()).ok_or(Error::::NoAvailableTokenId)?; @@ -239,7 +263,7 @@ impl Pallet { })?; let token_info = TokenInfo { - metadata, + metadata: bounded_metadata, owner: owner.clone(), data, }; diff --git a/nft/src/mock.rs b/nft/src/mock.rs index 915f67561..e1f708a25 100644 --- a/nft/src/mock.rs +++ b/nft/src/mock.rs @@ -43,11 +43,18 @@ impl frame_system::Config for Runtime { type OnSetCode = (); } +parameter_types! { + pub const MaxClassMetadata: u32 = 1; + pub const MaxTokenMetadata: u32 = 1; +} + impl Config for Runtime { type ClassId = u64; type TokenId = u64; type ClassData = (); type TokenData = (); + type MaxClassMetadata = MaxClassMetadata; + type MaxTokenMetadata = MaxTokenMetadata; } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; diff --git a/nft/src/tests.rs b/nft/src/tests.rs index 1e2654e40..c62354308 100644 --- a/nft/src/tests.rs +++ b/nft/src/tests.rs @@ -178,3 +178,18 @@ fn destroy_class_should_fail() { assert_eq!(Classes::::contains_key(CLASS_ID), false); }); } + +#[test] +fn exceeding_max_metadata_should_fail() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + NonFungibleTokenModule::create_class(&ALICE, vec![1, 2], ()), + Error::::MaxMetadataExceeded + ); + assert_ok!(NonFungibleTokenModule::create_class(&ALICE, vec![1], ())); + assert_noop!( + NonFungibleTokenModule::mint(&BOB, CLASS_ID, vec![1, 2], ()), + Error::::MaxMetadataExceeded + ); + }); +} diff --git a/rewards/src/lib.rs b/rewards/src/lib.rs index cd2acfb11..7d41ca823 100644 --- a/rewards/src/lib.rs +++ b/rewards/src/lib.rs @@ -5,7 +5,7 @@ mod mock; mod tests; use codec::{FullCodec, HasCompact}; -use frame_support::pallet_prelude::*; +use frame_support::{pallet_prelude::*, traits::MaxEncodedLen}; use orml_traits::RewardHandler; use sp_runtime::{ traits::{AtLeast32BitUnsigned, MaybeSerializeDeserialize, Member, Saturating, Zero}, @@ -17,7 +17,7 @@ use sp_std::{ }; /// The Reward Pool Info. -#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, Default)] +#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, Default, MaxEncodedLen)] pub struct PoolInfo { /// Total shares amount #[codec(compact)]