diff --git a/frame/nfts/src/benchmarking.rs b/frame/nfts/src/benchmarking.rs index 68252ebfc9cac..2be115f17a474 100644 --- a/frame/nfts/src/benchmarking.rs +++ b/frame/nfts/src/benchmarking.rs @@ -828,6 +828,7 @@ benchmarks_instance_pallet! { metadata: metadata.clone(), only_account: None, deadline: One::one(), + mint_price: Some(DepositBalanceOf::::min_value()), }; let message = Encode::encode(&mint_data); let signature = MultiSignature::Sr25519(sr25519_sign(0.into(), &caller_public, &message).unwrap()); @@ -835,7 +836,7 @@ benchmarks_instance_pallet! { let target: T::AccountId = account("target", 0, SEED); T::Currency::make_free_balance_be(&target, DepositBalanceOf::::max_value()); frame_system::Pallet::::set_block_number(One::one()); - }: _(SystemOrigin::Signed(target.clone()), mint_data, signature.into(), caller) + }: _(SystemOrigin::Signed(target.clone()), Box::new(mint_data), signature.into(), caller) verify { let metadata: BoundedVec<_, _> = metadata.try_into().unwrap(); assert_last_event::(Event::ItemMetadataSet { collection, item, data: metadata }.into()); diff --git a/frame/nfts/src/features/create_delete_item.rs b/frame/nfts/src/features/create_delete_item.rs index 2aa27dc066619..a757273445f13 100644 --- a/frame/nfts/src/features/create_delete_item.rs +++ b/frame/nfts/src/features/create_delete_item.rs @@ -16,7 +16,7 @@ // limitations under the License. use crate::*; -use frame_support::pallet_prelude::*; +use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; impl, I: 'static> Pallet { pub fn do_mint( @@ -91,8 +91,15 @@ impl, I: 'static> Pallet { mint_data: PreSignedMintOf, signer: T::AccountId, ) -> DispatchResult { - let PreSignedMint { collection, item, attributes, metadata, deadline, only_account } = - mint_data; + let PreSignedMint { + collection, + item, + attributes, + metadata, + deadline, + only_account, + mint_price, + } = mint_data; let metadata = Self::construct_metadata(metadata)?; ensure!( @@ -118,7 +125,17 @@ impl, I: 'static> Pallet { Some(mint_to.clone()), mint_to.clone(), item_config, - |_, _| Ok(()), + |collection_details, _| { + if let Some(price) = mint_price { + T::Currency::transfer( + &mint_to, + &collection_details.owner, + price, + ExistenceRequirement::KeepAlive, + )?; + } + Ok(()) + }, )?; let admin_account = Self::find_account_by_role(&collection, CollectionRole::Admin); if let Some(admin_account) = admin_account { diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index 4796819df6d2c..1a068b95e2a73 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -1835,13 +1835,13 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::mint_pre_signed(mint_data.attributes.len() as u32))] pub fn mint_pre_signed( origin: OriginFor, - mint_data: PreSignedMintOf, + mint_data: Box>, signature: T::OffchainSignature, signer: T::AccountId, ) -> DispatchResult { let origin = ensure_signed(origin)?; Self::validate_signature(&Encode::encode(&mint_data), &signature, &signer)?; - Self::do_mint_pre_signed(origin, mint_data, signer) + Self::do_mint_pre_signed(origin, *mint_data, signer) } /// Set attributes for an item by providing the pre-signed approval. diff --git a/frame/nfts/src/tests.rs b/frame/nfts/src/tests.rs index 4ab12f0506056..55bcf57e8aaff 100644 --- a/frame/nfts/src/tests.rs +++ b/frame/nfts/src/tests.rs @@ -3146,13 +3146,14 @@ fn validate_signature() { let user_1_pair = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap(); let user_1_signer = MultiSigner::Sr25519(user_1_pair.public()); let user_1 = user_1_signer.clone().into_account(); - let mint_data: PreSignedMint = PreSignedMint { + let mint_data: PreSignedMint = PreSignedMint { collection: 0, item: 0, attributes: vec![], metadata: vec![], only_account: None, deadline: 100000, + mint_price: None, }; let encoded_data = Encode::encode(&mint_data); let signature = MultiSignature::Sr25519(user_1_pair.sign(&encoded_data)); @@ -3182,6 +3183,7 @@ fn pre_signed_mints_should_work() { metadata: vec![0, 1], only_account: None, deadline: 10000000, + mint_price: Some(10), }; let message = Encode::encode(&mint_data); let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); @@ -3198,7 +3200,7 @@ fn pre_signed_mints_should_work() { assert_ok!(Nfts::mint_pre_signed( RuntimeOrigin::signed(user_2.clone()), - mint_data.clone(), + Box::new(mint_data.clone()), signature.clone(), user_1.clone(), )); @@ -3228,13 +3230,13 @@ fn pre_signed_mints_should_work() { assert_eq!(deposit.account, Some(user_2.clone())); assert_eq!(deposit.amount, 3); - assert_eq!(Balances::free_balance(&user_0), 100 - 2); // 2 - collection deposit - assert_eq!(Balances::free_balance(&user_2), 100 - 1 - 3 - 6); // 1 - item deposit, 3 - metadata, 6 - attributes + assert_eq!(Balances::free_balance(&user_0), 100 - 2 + 10); // 2 - collection deposit, 10 - mint price + assert_eq!(Balances::free_balance(&user_2), 100 - 1 - 3 - 6 - 10); // 1 - item deposit, 3 - metadata, 6 - attributes, 10 - mint price assert_noop!( Nfts::mint_pre_signed( RuntimeOrigin::signed(user_2.clone()), - mint_data, + Box::new(mint_data), signature.clone(), user_1.clone(), ), @@ -3242,7 +3244,7 @@ fn pre_signed_mints_should_work() { ); assert_ok!(Nfts::burn(RuntimeOrigin::signed(user_2.clone()), 0, 0)); - assert_eq!(Balances::free_balance(&user_2), 100 - 6); + assert_eq!(Balances::free_balance(&user_2), 100 - 6 - 10); // validate the `only_account` field let mint_data = PreSignedMint { @@ -3252,13 +3254,14 @@ fn pre_signed_mints_should_work() { metadata: vec![], only_account: Some(account(2)), deadline: 10000000, + mint_price: None, }; // can't mint with the wrong signature assert_noop!( Nfts::mint_pre_signed( RuntimeOrigin::signed(user_2.clone()), - mint_data.clone(), + Box::new(mint_data.clone()), signature.clone(), user_1.clone(), ), @@ -3271,7 +3274,7 @@ fn pre_signed_mints_should_work() { assert_noop!( Nfts::mint_pre_signed( RuntimeOrigin::signed(user_3), - mint_data.clone(), + Box::new(mint_data.clone()), signature.clone(), user_1.clone(), ), @@ -3283,7 +3286,7 @@ fn pre_signed_mints_should_work() { assert_noop!( Nfts::mint_pre_signed( RuntimeOrigin::signed(user_2.clone()), - mint_data, + Box::new(mint_data), signature, user_1.clone(), ), @@ -3299,6 +3302,7 @@ fn pre_signed_mints_should_work() { metadata: vec![], only_account: Some(account(2)), deadline: 10000000, + mint_price: None, }; let message = Encode::encode(&mint_data); let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); @@ -3306,7 +3310,7 @@ fn pre_signed_mints_should_work() { assert_noop!( Nfts::mint_pre_signed( RuntimeOrigin::signed(user_2.clone()), - mint_data, + Box::new(mint_data), signature, user_1.clone(), ), @@ -3321,13 +3325,14 @@ fn pre_signed_mints_should_work() { metadata: vec![0, 1], only_account: None, deadline: 10000000, + mint_price: None, }; let message = Encode::encode(&mint_data); let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); assert_noop!( Nfts::mint_pre_signed( RuntimeOrigin::signed(user_2), - mint_data, + Box::new(mint_data), signature, user_1.clone(), ), diff --git a/frame/nfts/src/types.rs b/frame/nfts/src/types.rs index 8f36acd286c28..bea1eca1f4832 100644 --- a/frame/nfts/src/types.rs +++ b/frame/nfts/src/types.rs @@ -66,6 +66,7 @@ pub(super) type PreSignedMintOf = PreSignedMint< >::ItemId, ::AccountId, ::BlockNumber, + BalanceOf, >; pub(super) type PreSignedAttributesOf = PreSignedAttributes< >::CollectionId, @@ -506,7 +507,7 @@ impl CollectionRoles { impl_codec_bitflags!(CollectionRoles, u8, CollectionRole); #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct PreSignedMint { +pub struct PreSignedMint { /// A collection of the item to be minted. pub(super) collection: CollectionId, /// Item's ID. @@ -519,6 +520,8 @@ pub struct PreSignedMint { pub(super) only_account: Option, /// A deadline for the signature. pub(super) deadline: Deadline, + /// An optional price the claimer would need to pay for the mint. + pub(super) mint_price: Option, } #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]