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

[PLAT-762] Move NFT transfer extrinsics #245

Merged
merged 5 commits into from
Mar 28, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 11 additions & 1 deletion pallets/ajuna-awesome-avatars/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,15 @@ benchmarks! {
assert_last_event::<T>(Event::OrganizerSet { organizer }.into())
}

set_collection_id {
let organizer = account::<T>("organizer");
Organizer::<T>::put(&organizer);
let collection_id = CollectionIdOf::<T>::unique_saturated_from(u64::MAX);
}: _(RawOrigin::Signed(organizer), collection_id.clone())
verify {
assert_last_event::<T>(Event::CollectionIdSet { collection_id }.into())
}

set_treasurer {
let season_id = 369;
let treasurer = account::<T>("treasurer");
Expand Down Expand Up @@ -330,7 +339,8 @@ benchmarks! {
},
account: AccountConfig {
storage_upgrade_fee: BalanceOf::<T>::unique_saturated_from(u128::MAX),
}
},
nft_transfer: NftTransferConfig { open: true },
};
}: _(RawOrigin::Signed(organizer), config.clone())
verify {
Expand Down
50 changes: 42 additions & 8 deletions pallets/ajuna-awesome-avatars/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ pub mod pallet {
Avatar,
<T as Config>::AvatarNftConfig,
>>::AssetId;
pub(crate) type CollectionIdOf<T> = <<T as Config>::NftHandler as NftHandler<
AccountIdOf<T>,
Avatar,
<T as Config>::AvatarNftConfig,
>>::CollectionId;

pub(crate) const MAX_PERCENTAGE: u8 = 100;

Expand Down Expand Up @@ -177,6 +182,10 @@ pub mod pallet {
#[pallet::getter(fn locked_avatars)]
pub type LockedAvatars<T: Config> = StorageMap<_, Identity, AvatarIdOf<T>, AssetIdOf<T>>;

#[pallet::storage]
#[pallet::getter(fn collection_id)]
pub type CollectionId<T: Config> = StorageValue<_, CollectionIdOf<T>, OptionQuery>;

#[pallet::storage]
#[pallet::getter(fn accounts)]
pub type Accounts<T: Config> =
Expand Down Expand Up @@ -233,6 +242,7 @@ pub mod pallet {
account: AccountConfig {
storage_upgrade_fee: 1_000_000_000_000_u64.unique_saturated_into(), // 1 BAJU
},
nft_transfer: NftTransferConfig { open: true },
});
}
}
Expand All @@ -242,6 +252,8 @@ pub mod pallet {
pub enum Event<T: Config> {
/// An organizer has been set.
OrganizerSet { organizer: T::AccountId },
/// A collection ID has been set.
CollectionIdSet { collection_id: CollectionIdOf<T> },
/// A treasurer has been set for a season.
TreasurerSet { season_id: SeasonId, treasurer: T::AccountId },
/// A season's treasury has been claimed by a treasurer.
Expand Down Expand Up @@ -282,6 +294,8 @@ pub mod pallet {
pub enum Error<T> {
/// There is no account set as the organizer
OrganizerNotSet,
/// There is no collection ID set for NFT handler.
CollectionIdNotSet,
/// The season starts before the previous season has ended.
EarlyStartTooEarly,
/// The season season start later than its early access
Expand Down Expand Up @@ -323,6 +337,8 @@ pub mod pallet {
TransferClosed,
/// Trading is not available at the moment.
TradeClosed,
/// NFT transfer is not available at the moment.
NftTransferClosed,
/// Attempt to mint or forge outside of an active season.
SeasonClosed,
/// Attempt to mint when the season has ended prematurely.
Expand Down Expand Up @@ -752,35 +768,53 @@ pub mod pallet {

#[pallet::call_index(14)]
#[pallet::weight(10_000)]
pub fn set_collection_id(
origin: OriginFor<T>,
collection_id: CollectionIdOf<T>,
) -> DispatchResult {
Self::ensure_organizer(origin)?;
CollectionId::<T>::put(&collection_id);
Self::deposit_event(Event::CollectionIdSet { collection_id });
Ok(())
}

#[pallet::call_index(15)]
#[pallet::weight(10_000)]
pub fn lock_avatar(origin: OriginFor<T>, avatar_id: AvatarIdOf<T>) -> DispatchResult {
let account = ensure_signed(origin)?;
let avatar = Self::ensure_ownership(&account, &avatar_id)?;
let player = ensure_signed(origin)?;
let avatar = Self::ensure_ownership(&player, &avatar_id)?;
ensure!(Self::ensure_for_trade(&avatar_id).is_err(), Error::<T>::AvatarInTrade);
ensure!(Self::global_configs().nft_transfer.open, Error::<T>::NftTransferClosed);
Self::ensure_unlocked(&avatar_id)?;

// TODO: Use a defined config, either as parameter or as a constant in the pallet config
let asset_config = T::AvatarNftConfig::default();
let asset_id = T::NftHandler::store_as_nft(account, avatar, asset_config)?;
let collection_id = Self::collection_id().ok_or(Error::<T>::CollectionIdNotSet)?;
let asset_id =
T::NftHandler::store_as_nft(player, collection_id, avatar, asset_config)?;
LockedAvatars::<T>::insert(avatar_id, &asset_id);
Self::deposit_event(Event::AvatarLocked { avatar_id, asset_id });
Ok(())
}

#[pallet::call_index(15)]
#[pallet::call_index(16)]
#[pallet::weight(10_000)]
pub fn unlock_avatar(origin: OriginFor<T>, avatar_id: AvatarIdOf<T>) -> DispatchResult {
let account = ensure_signed(origin)?;
let _ = Self::ensure_ownership(&account, &avatar_id)?;
let player = ensure_signed(origin)?;
let _ = Self::ensure_ownership(&player, &avatar_id)?;
ensure!(Self::ensure_for_trade(&avatar_id).is_err(), Error::<T>::AvatarInTrade);
ensure!(Self::global_configs().nft_transfer.open, Error::<T>::NftTransferClosed);

let collection_id = Self::collection_id().ok_or(Error::<T>::CollectionIdNotSet)?;
let asset_id = Self::locked_avatars(avatar_id).ok_or(Error::<T>::AvatarUnlocked)?;
let _ = T::NftHandler::recover_from_nft(account, asset_id)?;
let _ = T::NftHandler::recover_from_nft(player, collection_id, asset_id)?;

LockedAvatars::<T>::remove(avatar_id);
Self::deposit_event(Event::AvatarUnlocked { avatar_id });
Ok(())
}

#[pallet::call_index(16)]
#[pallet::call_index(17)]
#[pallet::weight(T::WeightInfo::fix_variation())]
pub fn fix_variation(origin: OriginFor<T>, avatar_id: AvatarIdOf<T>) -> DispatchResult {
let account = ensure_signed(origin)?;
Expand Down
3 changes: 2 additions & 1 deletion pallets/ajuna-awesome-avatars/src/migration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@
pub mod v1;
pub mod v2;
pub mod v3;
pub mod v4;

use super::*;
use frame_support::traits::OnRuntimeUpgrade;

// The current storage version.
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(3);
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(4);

const LOG_TARGET: &str = "runtime::ajuna-awesome-avatars";
2 changes: 1 addition & 1 deletion pallets/ajuna-awesome-avatars/src/migration/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
},
);
current_version.put::<Pallet<T>>();
log::info!(target: LOG_TARGET, "Upgraded storage to version {:?}", current_version,);
log::info!(target: LOG_TARGET, "Upgraded storage to version {:?}", current_version);
T::DbWeight::get().reads_writes(2, 2)
} else {
log::info!(
Expand Down
27 changes: 23 additions & 4 deletions pallets/ajuna-awesome-avatars/src/migration/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,32 @@ pub struct OldGlobalConfig<T: Config> {
pub account: AccountConfig<BalanceOf<T>>,
}

#[derive(Decode, Encode, Default)]
pub struct GlobalConfigV2<Balance, BlockNumber> {
pub mint: MintConfig<Balance, BlockNumber>,
pub forge: ForgeConfig,
pub transfer: TransferConfig<Balance>,
pub trade: TradeConfig<Balance>,
pub account: AccountConfig<Balance>,
}

impl<T: Config> OldGlobalConfig<T> {
fn migrate_to_v2(self) -> GlobalConfig<BalanceOf<T>, T::BlockNumber> {
fn migrate_to_v2(self) -> GlobalConfigV2<BalanceOf<T>, T::BlockNumber> {
let (mint, transfer) = self.mint.migrate_to_v2();
GlobalConfig { mint, forge: self.forge, transfer, trade: self.trade, account: self.account }
GlobalConfigV2 {
mint,
forge: self.forge,
transfer,
trade: self.trade,
account: self.account,
}
}
}

#[frame_support::storage_alias]
pub(crate) type GlobalConfigs<T: Config> =
StorageValue<Pallet<T>, GlobalConfigV2<BalanceOf<T>, BlockNumberFor<T>>, ValueQuery>;

pub struct MigrateToV2<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV2<T> {
fn on_runtime_upgrade() -> Weight {
Expand All @@ -75,7 +94,7 @@ impl<T: Config> OnRuntimeUpgrade for MigrateToV2<T> {
})
});
current_version.put::<Pallet<T>>();
log::info!(target: LOG_TARGET, "Upgraded storage to version {:?}", current_version,);
log::info!(target: LOG_TARGET, "Upgraded storage to version {:?}", current_version);
T::DbWeight::get().reads_writes(2, 2)
} else {
log::info!(
Expand All @@ -89,7 +108,7 @@ impl<T: Config> OnRuntimeUpgrade for MigrateToV2<T> {
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
assert_eq!(Pallet::<T>::on_chain_storage_version(), 2);
let GlobalConfig { transfer, .. } = GlobalConfigs::<T>::get();
let GlobalConfigV2 { transfer, .. } = GlobalConfigs::<T>::get();
assert!(transfer.open);
assert_eq!(transfer.avatar_transfer_fee, 1_000_000_000_000_u64.unique_saturated_into());
Ok(())
Expand Down
72 changes: 72 additions & 0 deletions pallets/ajuna-awesome-avatars/src/migration/v4.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Ajuna Node
// Copyright (C) 2022 BlogaTech AG

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

use super::*;

#[derive(Decode, Encode, Default)]
pub struct OldGlobalConfig<T: Config> {
pub mint: MintConfig<BalanceOf<T>, T::BlockNumber>,
pub forge: ForgeConfig,
pub transfer: TransferConfig<BalanceOf<T>>,
pub trade: TradeConfig<BalanceOf<T>>,
pub account: AccountConfig<BalanceOf<T>>,
}

impl<T: Config> OldGlobalConfig<T> {
fn migrate_to_v4(self) -> GlobalConfig<BalanceOf<T>, T::BlockNumber> {
GlobalConfig {
mint: self.mint,
forge: self.forge,
transfer: self.transfer,
trade: self.trade,
account: self.account,
nft_transfer: NftTransferConfig { open: true },
}
}
}

pub struct MigrateToV4<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV4<T> {
fn on_runtime_upgrade() -> Weight {
let current_version = Pallet::<T>::current_storage_version();
let onchain_version = Pallet::<T>::on_chain_storage_version();
if onchain_version == 3 && current_version == 4 {
let _ = GlobalConfigs::<T>::translate::<OldGlobalConfig<T>, _>(|maybe_old_value| {
maybe_old_value.map(|old_value| {
log::info!(target: LOG_TARGET, "Migrated global config");
old_value.migrate_to_v4()
})
});
current_version.put::<Pallet<T>>();
log::info!(target: LOG_TARGET, "Upgraded storage to version {:?}", current_version);
T::DbWeight::get().reads_writes(2, 2)
} else {
log::info!(
target: LOG_TARGET,
"Migration did not execute. This probably should be removed"
);
T::DbWeight::get().reads(1)
}
}

#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
assert_eq!(Pallet::<T>::on_chain_storage_version(), 4);
let GlobalConfig { nft_transfer, .. } = GlobalConfigs::<T>::get();
assert!(nft_transfer.open);
Ok(())
}
}
10 changes: 1 addition & 9 deletions pallets/ajuna-awesome-avatars/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,6 @@ parameter_types! {

impl pallet_ajuna_nft_transfer::Config for Test {
type RuntimeEvent = RuntimeEvent;
#[cfg(feature = "runtime-benchmarks")]
type Currency = Balances;
type MaxAssetEncodedSize = ValueLimit;
type CollectionId = MockCollectionId;
type CollectionConfig =
Expand All @@ -179,7 +177,6 @@ impl pallet_ajuna_nft_transfer::Config for Test {
type ItemConfig = pallet_nfts::ItemConfig;
type NftHelper = Nft;
type HoldingPalletId = HoldingPalletId;
type WeightInfo = ();
}

pub struct ExtBuilder {
Expand Down Expand Up @@ -307,12 +304,7 @@ impl ExtBuilder {
&pallet_nfts::CollectionConfig::default(),
)
.expect("Collection created");
assert!(NftTransfer::set_organizer(RuntimeOrigin::root(), ALICE).is_ok());
assert!(NftTransfer::set_holding_collection_id(
RuntimeOrigin::signed(ALICE),
collection_id
)
.is_ok())
CollectionId::<Test>::put(collection_id);
}
});
ext
Expand Down
Loading