Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: nft bench + remove emote #138

Merged
merged 4 commits into from Aug 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Expand Up @@ -120,7 +120,6 @@ Then open settings screen -> developer and paste
},
"TokenData": {
"locked": "bool",
"emote": "Vec<u8>"
},
"CID": "Vec<u8>",
"ClassInfo": {
Expand Down
26 changes: 10 additions & 16 deletions pallets/nft/src/benchmarking.rs
Expand Up @@ -53,15 +53,14 @@ benchmarks! {
mint {
let caller = create_account::<T>("caller", 0);
let big_vec = vec![1; <T as orml_nft::Config>::MaxClassMetadata::get() as usize];
let big_emote = vec![1; T::MaxEmoteLength::get() as usize];
let class_metadata = big_vec.clone();
let token_data = TokenData { locked:false, emote:big_emote };
let token_data = TokenData { locked:false };
let class_data = ClassData { is_pool:false };
NFT::Pallet::<T>::create_class(RawOrigin::Signed(caller.clone()).into(), class_metadata.clone(), class_data).unwrap_or_default();
let class_id = 0u32.into();
let token_id = orml_nft::Pallet::<T>::next_token_id(class_id);
let token = (class_id, token_id);
}: _(RawOrigin::Signed(caller.clone()), class_id, class_metadata, token_data, 1u32.into())
}: _(RawOrigin::Signed(caller.clone()), class_id, class_metadata, token_data)
verify {
assert_eq!(orml_nft::Pallet::<T>::tokens_by_owner((caller, token.0, token.1)), ());
}
Expand All @@ -70,13 +69,12 @@ benchmarks! {
let caller = create_account::<T>("caller", 0);
let caller2 = create_account::<T>("caller2", 1);
let big_vec = vec![1; <T as orml_nft::Config>::MaxClassMetadata::get() as usize];
let big_emote = vec![1; T::MaxEmoteLength::get() as usize];
let class_metadata = big_vec.clone();
let class_data = ClassData { is_pool:false };
let token_data = TokenData { locked:false, emote:big_emote };
let token_data = TokenData { locked:false };
NFT::Pallet::<T>::create_class(RawOrigin::Signed(caller.clone()).into(), class_metadata.clone(), class_data).unwrap_or_default();
let class_id = 0u32.into();
NFT::Pallet::<T>::mint(RawOrigin::Signed(caller.clone()).into(), class_id, class_metadata.clone(), token_data, T::MintMaxQuantity::get()).unwrap_or_default();
NFT::Pallet::<T>::mint(RawOrigin::Signed(caller.clone()).into(), class_id, class_metadata.clone(), token_data).unwrap_or_default();
let token_id = 0u32.into();
let token = (class_id, token_id);
}: _(RawOrigin::Signed(caller.clone()), T::Lookup::unlookup(caller2.clone()), token)
Expand Down Expand Up @@ -112,13 +110,12 @@ benchmarks! {
burn {
let caller = create_account::<T>("caller", 0);
let big_vec = vec![1; <T as orml_nft::Config>::MaxClassMetadata::get() as usize];
let big_emote = vec![1; T::MaxEmoteLength::get() as usize];
let class_metadata = big_vec.clone();
let class_data = ClassData { is_pool:true };
let token_data = TokenData { locked:false, emote:big_emote };
let token_data = TokenData { locked:false };
NFT::Pallet::<T>::create_class(RawOrigin::Signed(caller.clone()).into(), class_metadata.clone(), class_data).unwrap_or_default();
let class_id = 0u32.into();
NFT::Pallet::<T>::mint(RawOrigin::Signed(caller.clone()).into(), class_id, class_metadata.clone(), token_data, T::MintMaxQuantity::get()).unwrap_or_default();
NFT::Pallet::<T>::mint(RawOrigin::Signed(caller.clone()).into(), class_id, class_metadata.clone(), token_data).unwrap_or_default();
let token_id = 0u32.into();
let token = (class_id, token_id);
}: _(RawOrigin::Signed(caller.clone()), token)
Expand All @@ -130,13 +127,12 @@ benchmarks! {
let caller = create_account::<T>("caller", 0);
let caller2 = create_account::<T>("caller2", 1);
let big_vec = vec![1; <T as orml_nft::Config>::MaxClassMetadata::get() as usize];
let big_emote = vec![1; T::MaxEmoteLength::get() as usize];
let class_metadata = big_vec.clone();
let class_data = ClassData { is_pool:true };
let token_data = TokenData { locked:false, emote:big_emote };
let token_data = TokenData { locked:false };
NFT::Pallet::<T>::create_class(RawOrigin::Signed(caller.clone()).into(), class_metadata.clone(), class_data).unwrap_or_default();
let class_id = 0u32.into();
NFT::Pallet::<T>::mint(RawOrigin::Signed(caller.clone()).into(), class_id, class_metadata.clone(), token_data, T::MintMaxQuantity::get()).unwrap_or_default();
NFT::Pallet::<T>::mint(RawOrigin::Signed(caller.clone()).into(), class_id, class_metadata.clone(), token_data).unwrap_or_default();
let token_id = 0u32.into();
let token = (class_id, token_id);
}: _(RawOrigin::Signed(caller2.clone()), token)
Expand All @@ -149,13 +145,12 @@ benchmarks! {
let caller = create_account::<T>("caller", 0);
let caller2 = create_account::<T>("caller2", 1);
let big_vec = vec![1; <T as orml_nft::Config>::MaxClassMetadata::get() as usize];
let big_emote = vec![1; T::MaxEmoteLength::get() as usize];
let class_metadata = big_vec.clone();
let class_data = ClassData { is_pool:true };
let token_data = TokenData { locked:false, emote:big_emote };
let token_data = TokenData { locked:false };
NFT::Pallet::<T>::create_class(RawOrigin::Signed(caller.clone()).into(), class_metadata.clone(), class_data).unwrap_or_default();
let class_id = 0u32.into();
NFT::Pallet::<T>::mint(RawOrigin::Signed(caller.clone()).into(), class_id, class_metadata.clone(), token_data, T::MintMaxQuantity::get()).unwrap_or_default();
NFT::Pallet::<T>::mint(RawOrigin::Signed(caller.clone()).into(), class_id, class_metadata.clone(), token_data).unwrap_or_default();
let token_id = 0u32.into();
let token = (class_id, token_id);
NFT::Pallet::<T>::transfer(RawOrigin::Signed(caller.clone()).into(), T::Lookup::unlookup(caller2.clone()), token).unwrap_or_default();
Expand All @@ -164,7 +159,6 @@ benchmarks! {
let sold_token = orml_nft::Pallet::<T>::tokens(class_id, token_id);
assert_eq!(sold_token.unwrap().owner, caller);
}

}

#[cfg(test)]
Expand Down
74 changes: 43 additions & 31 deletions pallets/nft/src/lib.rs
Expand Up @@ -33,14 +33,13 @@ pub type ClassIdOf<T> = <T as orml_nft::Config>::ClassId;
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
#[derive(Encode, Decode, RuntimeDebug, Clone, PartialEq, Eq)]
pub struct ClassData {
pub is_pool: bool,
pub is_pool: bool, // NFT pools for tokenized merch
}

#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
#[derive(Encode, Decode, RuntimeDebug, Clone, PartialEq, Eq)]
pub struct TokenData {
pub locked: bool,
pub emote: Vec<u8>,
pub locked: bool, // token locking will be used in the nft auctions
}

// Re-export pallet items so that they can be accessed from the crate namespace.
Expand Down Expand Up @@ -68,12 +67,6 @@ pub mod pallet {
// How much will be bonded
#[pallet::constant]
type ClassBondAmount: Get<BalanceOf<Self>>;
// Maximum amount of minted NFTs in a collection
#[pallet::constant]
type MintMaxQuantity: Get<u32>;
// Maximum length of emote
#[pallet::constant]
type MaxEmoteLength: Get<u32>;
}

#[pallet::call]
Expand All @@ -87,6 +80,10 @@ pub mod pallet {
/// Creates an NFT class
/// This is necessary as the first step, because tokens will be minted as part of this class
/// An amount X (ClassBondAmount) is reserved
///
/// Parameters:
/// - `metadata`: Arbitrary info/description of a class
/// - `data`: Field(s) defined in the ClassData struct
#[pallet::weight(<T as Config>::WeightInfo::create_class())]
#[transactional]
pub fn create_class(origin: OriginFor<T>, metadata: Vec<u8>, data: T::ClassData) -> DispatchResultWithPostInfo {
Expand All @@ -99,38 +96,37 @@ pub mod pallet {
Ok(().into())
}

/// A particular amount (quantity) of NFTs are minted in the specified class
/// The weight is increased linearly for each minted token
#[pallet::weight(<T as Config>::WeightInfo::mint(*quantity))]
/// NFT is minted in the specified class
///
/// Parameters:
/// - `class_id`: identificator of a class
/// - `metadata`: Arbitrary info/description of a token
/// - `data`: Field(s) defined in the TokenData struct
#[pallet::weight(<T as Config>::WeightInfo::mint())]
#[transactional]
pub fn mint(
origin: OriginFor<T>,
class_id: ClassIdOf<T>,
metadata: Vec<u8>,
token_data: TokenData,
quantity: u32,
token_data: TokenData
) -> DispatchResultWithPostInfo {
let sender = ensure_signed(origin)?;
ensure!(
quantity > Zero::zero() && T::MintMaxQuantity::get() >= quantity,
Error::<T>::InvalidQuantity
);
ensure!(
token_data.emote.len() <= (T::MaxEmoteLength::get() as usize),
Error::<T>::EmoteTooLong
);

let class_info = orml_nft::Pallet::<T>::classes(class_id).ok_or(Error::<T>::ClassNotFound)?;
ensure!(sender == class_info.owner, Error::<T>::NotClassOwner);
let data = token_data;
for _ in 0..quantity {
orml_nft::Pallet::<T>::mint(&sender, class_id, metadata.clone(), data.clone())?;
}
Self::deposit_event(Event::TokenMinted(sender, class_id, quantity));
let token_id = orml_nft::Pallet::<T>::mint(&sender, class_id, metadata.clone(), data.clone())?;

Self::deposit_event(Event::TokenMinted(sender, class_id, token_id));
Ok(().into())
}

/// Transfers NFT from account A to account B
/// Only the owner can send their NFT to another account
///
/// Parameters:
/// - `dest`: The destination account a token will be sent to
/// - `token`: unique identificator of a token
#[pallet::weight(<T as Config>::WeightInfo::transfer())]
#[transactional]
pub fn transfer(
Expand All @@ -150,6 +146,9 @@ pub mod pallet {
}

/// Removes a token from existence
///
/// Parameters:
/// - `token`: unique identificator of a token
#[pallet::weight(<T as Config>::WeightInfo::burn())]
#[transactional]
pub fn burn(origin: OriginFor<T>, token: (T::ClassId, T::TokenId)) -> DispatchResultWithPostInfo {
Expand All @@ -164,6 +163,9 @@ pub mod pallet {

/// Removes a class from existence
/// Returns the bond amount
///
/// Parameters:
/// - `class_id`: unique identificator of a class
#[pallet::weight(<T as Config>::WeightInfo::destroy_class())]
#[transactional]
pub fn destroy_class(origin: OriginFor<T>, class_id: ClassIdOf<T>) -> DispatchResultWithPostInfo {
Expand All @@ -186,6 +188,11 @@ pub mod pallet {
/// The difference between a pool and a class in this case is that
/// a price has to be specified for each pool. Any NFT within this class
/// will have this exact constant price
///
/// Parameters:
/// - `metadata`: Arbitrary info/description of a pool
/// - `data`: Field(s) defined in the ClassData struct
/// - `price`: Price of each individual NFT
#[pallet::weight(<T as Config>::WeightInfo::create_pool())]
#[transactional]
pub fn create_pool(
Expand All @@ -206,6 +213,9 @@ pub mod pallet {

/// Removes a pool from existence
/// Returns the bond amount
///
/// Parameters:
/// - `class_id`: unique identificator of a class
#[pallet::weight(<T as Config>::WeightInfo::destroy_class())]
#[transactional]
pub fn destroy_pool(origin: OriginFor<T>, class_id: ClassIdOf<T>) -> DispatchResultWithPostInfo {
Expand All @@ -220,6 +230,9 @@ pub mod pallet {
}

/// NFTs can be bought from a pool for a constant price
///
/// Parameters:
/// - `token`: unique identificator of a token
#[pallet::weight(<T as Config>::WeightInfo::buy_from_pool())]
#[transactional]
pub fn buy_from_pool(origin: OriginFor<T>, token: (ClassIdOf<T>, TokenIdOf<T>)) -> DispatchResult {
Expand All @@ -239,6 +252,9 @@ pub mod pallet {
}

/// Owned NFTs can be sold back to the pool for the original price
///
/// Parameters:
/// - `token`: unique identificator of a token
#[pallet::weight(<T as Config>::WeightInfo::sell_to_pool())]
#[transactional]
pub fn sell_to_pool(origin: OriginFor<T>, token: (ClassIdOf<T>, TokenIdOf<T>)) -> DispatchResult {
Expand All @@ -265,7 +281,7 @@ pub mod pallet {
#[pallet::generate_deposit(pub(crate) fn deposit_event)]
pub enum Event<T: Config> {
TokenClassCreated(T::AccountId, T::ClassId),
TokenMinted(T::AccountId, T::ClassId, u32),
TokenMinted(T::AccountId, T::ClassId, T::TokenId),
TokenMintedLockToggled(T::AccountId, T::ClassId, T::TokenId, bool),
TokenTransferred(T::AccountId, T::AccountId, T::ClassId, T::TokenId),
TokenBurned(T::AccountId, T::ClassId, T::TokenId),
Expand All @@ -290,8 +306,6 @@ pub mod pallet {
NonZeroIssuance,
/// Token is currently locked
TokenLocked,
/// Quantity has to be greater than zero
InvalidQuantity,
/// A token can not be transferred to self
CannotSendToSelf,
/// A user cannot buy already owned token
Expand All @@ -304,8 +318,6 @@ pub mod pallet {
NotAPool,
/// Metadata exceed the allowed length
MetadataTooLong,
/// Emote exceed the allowed length
EmoteTooLong,
}
}

Expand Down
6 changes: 0 additions & 6 deletions pallets/nft/src/mock.rs
Expand Up @@ -35,18 +35,14 @@ frame_support::construct_runtime!(

parameter_types! {
pub ClassBondAmount: Balance = 100;
pub MintMaxQuantity: u32 = 100_000;
pub MaxMetadataLength: u32 = 256;
pub MaxEmoteLength: u32 = 256;
}

impl pallet_nft::Config for Test {
type Currency = Balances;
type Event = Event;
type WeightInfo = pallet_nft::weights::HydraWeight<Test>;
type ClassBondAmount = ClassBondAmount;
type MintMaxQuantity = MintMaxQuantity;
type MaxEmoteLength = MaxEmoteLength;
}

parameter_types! {
Expand Down Expand Up @@ -117,8 +113,6 @@ pub const BOB: AccountId = AccountId::new([2u8; 32]);
pub const BSX: Balance = 100_000_000_000;
pub const CHARLIE: AccountId = AccountId::new([3u8; 32]);
pub const CLASS_ID: <Test as orml_nft::Config>::ClassId = 0;
pub const EMOTE: &str = "RMRK::EMOTE::RMRK1.0.0::0aff6865bed3a66b-VALHELLO-POTION_HEAL-0000000000000001::1F389";
pub const TEST_QUANTITY: u32 = 99;
pub const TEST_PRICE: Balance = 99;
pub const TOKEN_ID: <Test as orml_nft::Config>::TokenId = 0;

Expand Down