Skip to content
This repository has been archived by the owner on May 15, 2024. It is now read-only.

Commit

Permalink
Remove NFT collection generetaion from NFT-Staking genesis (#240)
Browse files Browse the repository at this point in the history
* * Remove contract holding collection from genesis
* Added new extrinsic for setting contract collection id

* * Clippy fixes

* * Clippy fixes

* Update pallets/ajuna-nft-staking/src/tests.rs

Co-authored-by: Eric <6591791+cowboy-bebug@users.noreply.github.com>

---------

Co-authored-by: Cedric Decoster <darkfriend77@users.noreply.github.com>
Co-authored-by: Eric <6591791+cowboy-bebug@users.noreply.github.com>
  • Loading branch information
3 people authored Mar 23, 2023
1 parent b1acfd1 commit 2a18df9
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 19 deletions.
37 changes: 36 additions & 1 deletion pallets/ajuna-nft-staking/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ fn create_contract_clause<T: Config>(attr_key: u32, attr_value: u64) -> Contract
)
}

fn create_staking_contract_collection<T: Config>(account: &T::AccountId) -> T::CollectionId {
let collection_config = <T as crate::pallet::Config>::ContractCollectionConfig::get();
<T as crate::pallet::Config>::NftHelper::create_collection(account, account, &collection_config)
.expect("Should have create contract collection")
}

type ContractClauseOf<T> = ContractClause<
<T as frame_system::Config>::AccountId,
<T as Config>::ContractAttributeKey,
Expand All @@ -158,6 +164,15 @@ benchmarks! {
assert_last_event::<T>(Event::OrganizerSet { organizer }.into())
}

set_contract_collection_id {
let account = NftStake::<T>::treasury_account_id();
let collection_id = create_staking_contract_collection::<T>(&account);
Organizer::<T>::put(&account);
}: _(RawOrigin::Signed(account), collection_id)
verify {
assert_last_event::<T>(Event::ContractCollectionSet { collection_id }.into())
}

set_locked_state {
let organizer = prepare_account::<T>("ALICE");
Organizer::<T>::put(&organizer);
Expand All @@ -175,6 +190,10 @@ benchmarks! {
}

submit_staking_contract_token_reward {
let account = NftStake::<T>::treasury_account_id();
let collection_id = create_staking_contract_collection::<T>(&account);
ContractCollectionId::<T>::put(collection_id);

let caller = prepare_account::<T>("ALICE");
let reward_amt: BalanceOf<T> = 1_000_u32.into();
let reward = StakingRewardOf::<T>::Tokens(reward_amt);
Expand All @@ -187,6 +206,10 @@ benchmarks! {
}

submit_staking_contract_nft_reward {
let account = NftStake::<T>::treasury_account_id();
let collection_id = create_staking_contract_collection::<T>(&account);
ContractCollectionId::<T>::put(collection_id);

let caller = prepare_account::<T>("ALICE");
let collection_id = create_random_nft_collection::<T>(caller.clone());
let nft_addr = create_random_nft::<T>(&caller, collection_id, 0_u32.into());
Expand All @@ -200,6 +223,10 @@ benchmarks! {
}

take_staking_contract {
let account = NftStake::<T>::treasury_account_id();
let collection_id = create_staking_contract_collection::<T>(&account);
ContractCollectionId::<T>::put(collection_id);

let caller = prepare_account::<T>("ALICE");
let reward_amt: BalanceOf<T> = 1_000_u32.into();
let reward = StakingRewardOf::<T>::Tokens(reward_amt);
Expand All @@ -220,6 +247,10 @@ benchmarks! {
}

redeem_staking_contract_token_reward {
let account = NftStake::<T>::treasury_account_id();
let collection_id = create_staking_contract_collection::<T>(&account);
ContractCollectionId::<T>::put(collection_id);

let caller = prepare_account::<T>("ALICE");
let reward_amt: BalanceOf<T> = 1_000_u32.into();
let reward = StakingRewardOf::<T>::Tokens(reward_amt);
Expand All @@ -243,6 +274,10 @@ benchmarks! {
}

redeem_staking_contract_nft_reward {
let account = NftStake::<T>::treasury_account_id();
let collection_id = create_staking_contract_collection::<T>(&account);
ContractCollectionId::<T>::put(collection_id);

let caller = prepare_account::<T>("ALICE");
let collection_id = create_random_nft_collection::<T>(caller.clone());
let reward_nft_addr = create_random_nft::<T>(&caller, collection_id, 0_u32.into());
Expand All @@ -267,6 +302,6 @@ benchmarks! {
}

impl_benchmark_test_suite!(
NftStake, crate::mock::ExtBuilder::default().build(), crate::mock::Test
NftStake, crate::mock::ExtBuilder::default().create_collection(true).build(), crate::mock::Test
);
}
47 changes: 32 additions & 15 deletions pallets/ajuna-nft-staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ pub mod pallet {
pub type TreasuryAccount<T: Config> = StorageValue<_, AccountIdOf<T>, OptionQuery>;

#[pallet::storage]
#[pallet::getter(fn contract_collection_id)]
pub type ContractCollectionId<T: Config> =
StorageValue<_, CollectionIdOf<T>, ResultQuery<Error<T>::ContractNotFound>>;

Expand Down Expand Up @@ -289,20 +290,16 @@ pub mod pallet {
if T::Currency::free_balance(&account_id) < min {
let _ = T::Currency::make_free_balance_be(&account_id, min);
}

let collection_config = T::ContractCollectionConfig::get();
let collection_id =
T::NftHelper::create_collection(&account_id, &account_id, &collection_config)
.expect("Should have create contract collection");
ContractCollectionId::<T>::put(collection_id);
}
}

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// An organizer has been set.
OrganizerSet { organizer: T::AccountId },
OrganizerSet { organizer: AccountIdOf<T> },
/// The collection holding the staking contracts has been set.
ContractCollectionSet { collection_id: T::CollectionId },
/// The pallet's lock status has been set
LockedStateSet { locked_state: PalletLockedState },
/// A new staking contract has been successfully created
Expand All @@ -324,6 +321,8 @@ pub mod pallet {
pub enum Error<T> {
/// There is no account set as the organizer
OrganizerNotSet,
/// The contract collection is either non-existent or not owned by the organizer.
InvalidContractCollection,
/// The pallet is currently locked and cannot be interacted with.
PalletLocked,
/// The treasury doesn't have enough funds to pay the contract rewards.
Expand Down Expand Up @@ -353,29 +352,47 @@ pub mod pallet {

#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::set_organizer())]
#[pallet::call_index(0)]
pub fn set_organizer(origin: OriginFor<T>, organizer: T::AccountId) -> DispatchResult {
ensure_root(origin)?;
Organizer::<T>::put(&organizer);
Self::deposit_event(Event::OrganizerSet { organizer });
Ok(())
}

#[pallet::weight(T::WeightInfo::set_contract_collection_id())]
#[pallet::call_index(1)]
pub fn set_contract_collection_id(
origin: OriginFor<T>,
collection_id: T::CollectionId,
) -> DispatchResult {
let account = Self::ensure_organizer(origin)?;
ensure!(
T::NftHelper::collection_owner(&collection_id)
.filter(|owner| *owner == account)
.is_some(),
Error::<T>::InvalidContractCollection
);
ContractCollectionId::<T>::put(collection_id);
Self::deposit_event(Event::ContractCollectionSet { collection_id });
Ok(())
}

#[pallet::weight(T::WeightInfo::set_locked_state())]
#[pallet::call_index(2)]
pub fn set_locked_state(
origin: OriginFor<T>,
locked_state: PalletLockedState,
) -> DispatchResult {
Self::ensure_organizer(origin)?;
let _ = Self::ensure_organizer(origin)?;
LockedState::<T>::put(locked_state);
Self::deposit_event(Event::LockedStateSet { locked_state });
Ok(())
}

#[pallet::weight(T::WeightInfo::fund_treasury())]
#[pallet::call_index(2)]
#[pallet::call_index(3)]
pub fn fund_treasury(origin: OriginFor<T>, fund_amount: BalanceOf<T>) -> DispatchResult {
let account = ensure_signed(origin)?;

Expand Down Expand Up @@ -404,7 +421,7 @@ pub mod pallet {
}

#[pallet::weight(T::WeightInfo::submit_staking_contract_nft_reward())]
#[pallet::call_index(3)]
#[pallet::call_index(4)]
pub fn submit_staking_contract(
origin: OriginFor<T>,
staking_contract: StakingContractOf<T>,
Expand Down Expand Up @@ -433,7 +450,7 @@ pub mod pallet {
}

#[pallet::weight(T::WeightInfo::take_staking_contract())]
#[pallet::call_index(4)]
#[pallet::call_index(5)]
pub fn take_staking_contract(
origin: OriginFor<T>,
contract_id: ContractItemIdOf<T>,
Expand Down Expand Up @@ -476,7 +493,7 @@ pub mod pallet {
}

#[pallet::weight(T::WeightInfo::redeem_staking_contract_nft_reward())]
#[pallet::call_index(5)]
#[pallet::call_index(6)]
pub fn redeem_staking_contract(
origin: OriginFor<T>,
contract_id: ContractItemIdOf<T>,
Expand Down Expand Up @@ -515,11 +532,11 @@ pub mod pallet {
}

impl<T: Config> Pallet<T> {
fn ensure_organizer(origin: OriginFor<T>) -> DispatchResult {
fn ensure_organizer(origin: OriginFor<T>) -> Result<AccountIdOf<T>, DispatchError> {
let maybe_organizer = ensure_signed(origin)?;
let existing_organizer = Self::organizer().ok_or(Error::<T>::OrganizerNotSet)?;
ensure!(maybe_organizer == existing_organizer, DispatchError::BadOrigin);
Ok(())
Ok(maybe_organizer)
}

fn ensure_unlocked() -> DispatchResult {
Expand Down
23 changes: 22 additions & 1 deletion pallets/ajuna-nft-staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use crate::{self as pallet_nft_staking, *};
use frame_support::{
parameter_types,
traits::{AsEnsureOriginWithArg, ConstU16, ConstU64, Hooks},
traits::{tokens::nonfungibles_v2::Create, AsEnsureOriginWithArg, ConstU16, ConstU64, Hooks},
};
use frame_system::{
mocking::{MockBlock, MockUncheckedExtrinsic},
Expand Down Expand Up @@ -175,6 +175,7 @@ impl pallet_nft_staking::Config for Test {

pub struct ExtBuilder {
balances: Vec<(MockAccountId, MockBalance)>,
create_collection: bool,
}

impl Default for ExtBuilder {
Expand All @@ -187,6 +188,7 @@ impl Default for ExtBuilder {
(BOB, accounts_balance),
(CHARLIE, accounts_balance),
],
create_collection: true,
}
}
}
Expand All @@ -197,6 +199,11 @@ impl ExtBuilder {
self
}

pub fn create_collection(mut self, create_collection: bool) -> Self {
self.create_collection = create_collection;
self
}

pub fn build(self) -> sp_io::TestExternalities {
let config = GenesisConfig {
system: Default::default(),
Expand All @@ -206,6 +213,20 @@ impl ExtBuilder {

let mut ext: sp_io::TestExternalities = config.build_storage().unwrap().into();
ext.execute_with(|| System::set_block_number(1));
if self.create_collection {
ext.execute_with(|| {
let account_id = <Pallet<Test>>::treasury_account_id();
let collection_config =
<Test as crate::pallet::Config>::ContractCollectionConfig::get();
let collection_id = <Test as crate::pallet::Config>::NftHelper::create_collection(
&account_id,
&account_id,
&collection_config,
)
.expect("Should have create contract collection");
ContractCollectionId::<Test>::put(collection_id);
});
}
ext
}
}
Expand Down
69 changes: 69 additions & 0 deletions pallets/ajuna-nft-staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,75 @@ mod organizer {
}
}

mod set_contract_collection_id {
use super::*;

#[test]
fn set_contract_collection_id_succesfully() {
ExtBuilder::default().create_collection(false).build().execute_with(|| {
assert!(NftStake::contract_collection_id().is_err());

assert_ok!(NftStake::set_organizer(RuntimeOrigin::root(), ALICE));

let collection_config =
<Test as crate::pallet::Config>::ContractCollectionConfig::get();
let collection_id = <Test as crate::pallet::Config>::NftHelper::create_collection(
&ALICE,
&ALICE,
&collection_config,
)
.expect("Should have create contract collection");

assert_ok!(NftStake::set_contract_collection_id(
RuntimeOrigin::signed(ALICE),
collection_id
));
assert_eq!(NftStake::contract_collection_id().unwrap(), collection_id);

System::assert_last_event(mock::RuntimeEvent::NftStake(
crate::Event::ContractCollectionSet { collection_id },
));
});
}

#[test]
fn set_contract_collection_id_should_reject_non_existing_collection() {
ExtBuilder::default().create_collection(false).build().execute_with(|| {
assert!(NftStake::contract_collection_id().is_err());

assert_ok!(NftStake::set_organizer(RuntimeOrigin::root(), ALICE));

assert_noop!(
NftStake::set_contract_collection_id(RuntimeOrigin::signed(ALICE), 17),
Error::<Test>::InvalidContractCollection
);
});
}

#[test]
fn set_contract_collection_id_should_reject_non_organizer_owned_collection() {
ExtBuilder::default().create_collection(false).build().execute_with(|| {
assert!(NftStake::contract_collection_id().is_err());

assert_ok!(NftStake::set_organizer(RuntimeOrigin::root(), ALICE));

let collection_config =
<Test as crate::pallet::Config>::ContractCollectionConfig::get();
let collection_id = <Test as crate::pallet::Config>::NftHelper::create_collection(
&BOB,
&ALICE,
&collection_config,
)
.expect("Should have created contract collection");

assert_noop!(
NftStake::set_contract_collection_id(RuntimeOrigin::signed(ALICE), collection_id),
Error::<Test>::InvalidContractCollection
);
});
}
}

mod set_lock_state {
use super::*;

Expand Down
Loading

0 comments on commit 2a18df9

Please sign in to comment.