Bladeren bron

Merge branch 'olympia' into update-playground

Mokhtar Naamani 3 jaren geleden
bovenliggende
commit
9d8a351e7e
35 gewijzigde bestanden met toevoegingen van 585 en 1191 verwijderingen
  1. 0 4
      node/src/chain_spec/mod.rs
  2. 10 10
      runtime-modules/content/src/errors.rs
  3. 107 278
      runtime-modules/content/src/lib.rs
  4. 16 16
      runtime-modules/content/src/nft/mod.rs
  5. 92 29
      runtime-modules/content/src/nft/types.rs
  6. 2 2
      runtime-modules/content/src/permissions/mod.rs
  7. 1 0
      runtime-modules/content/src/tests/fixtures.rs
  8. 1 0
      runtime-modules/content/src/tests/migration.rs
  9. 1 28
      runtime-modules/content/src/tests/mock.rs
  10. 1 1
      runtime-modules/content/src/tests/nft.rs
  11. 69 90
      runtime-modules/content/src/tests/nft/accept_incoming_offer.rs
  12. 11 21
      runtime-modules/content/src/tests/nft/buy_nft.rs
  13. 8 16
      runtime-modules/content/src/tests/nft/cancel_buy_now.rs
  14. 8 18
      runtime-modules/content/src/tests/nft/cancel_nft_auction.rs
  15. 7 15
      runtime-modules/content/src/tests/nft/cancel_offer.rs
  16. 10 24
      runtime-modules/content/src/tests/nft/cancel_open_auction_bid.rs
  17. 9 21
      runtime-modules/content/src/tests/nft/claim_won_english_auction.rs
  18. 67 29
      runtime-modules/content/src/tests/nft/issue_nft.rs
  19. 17 37
      runtime-modules/content/src/tests/nft/make_bid.rs
  20. 7 15
      runtime-modules/content/src/tests/nft/offer_nft.rs
  21. 9 21
      runtime-modules/content/src/tests/nft/pick_open_auction_winner.rs
  22. 8 16
      runtime-modules/content/src/tests/nft/sell_nft.rs
  23. 12 17
      runtime-modules/content/src/tests/nft/sling_nft_back.rs
  24. 8 18
      runtime-modules/content/src/tests/nft/start_nft_auction.rs
  25. 2 4
      runtime-modules/content/src/tests/videos.rs
  26. 17 153
      runtime-modules/content/src/types.rs
  27. 0 1
      runtime-modules/storage/src/benchmarking.rs
  28. 16 16
      runtime/src/constants.rs
  29. 0 6
      runtime/src/lib.rs
  30. 0 12
      runtime/src/primitives.rs
  31. 1 1
      runtime/src/runtime_api.rs
  32. 1 1
      scripts/generate-weights.sh
  33. 19 71
      types/augment/all/defs.json
  34. 24 107
      types/augment/all/types.ts
  35. 24 93
      types/src/content/index.ts

+ 0 - 4
node/src/chain_spec/mod.rs

@@ -276,11 +276,7 @@ pub fn testnet_genesis(
                 next_channel_id: 1,
                 next_video_category_id: 1,
                 next_video_id: 1,
-                next_playlist_id: 1,
-                next_series_id: 1,
-                next_person_id: 1,
                 next_video_post_id: 1,
-                next_channel_transfer_request_id: 1,
                 video_migration: node_runtime::content::MigrationConfigRecord {
                     current_id: 1,
                     final_id: 1,

+ 10 - 10
runtime-modules/content/src/errors.rs

@@ -79,17 +79,17 @@ decl_error! {
         /// Auction for given video did not start
         AuctionDidNotStart,
 
-        /// NFT for given video id already exists
-        NFTAlreadyExists,
+        /// Nft for given video id already exists
+        NftAlreadyExists,
 
-        /// NFT for given video id does not exist
-        NFTDoesNotExist,
+        /// Nft for given video id does not exist
+        NftDoesNotExist,
 
         /// Overflow or underflow error happened
         OverflowOrUnderflowHappened,
 
         /// Given origin does not own nft
-        DoesNotOwnNFT,
+        DoesNotOwnNft,
 
         /// Royalty Upper Bound Exceeded
         RoyaltyUpperBoundExceeded,
@@ -139,10 +139,10 @@ decl_error! {
         /// Already active auction cannot be cancelled
         ActionHasBidsAlready,
 
-        /// Can not create auction for NFT, if auction have been already started or nft is locked for the transfer
+        /// Can not create auction for Nft, if auction have been already started or nft is locked for the transfer
         NftIsNotIdle,
 
-        /// No pending offers for given NFT
+        /// No pending offers for given Nft
         PendingOfferDoesNotExist,
 
         /// Creator royalty requires reward account to be set.
@@ -173,7 +173,7 @@ decl_error! {
         MemberProfileNotFound,
 
         /// Given video nft is not in buy now state
-        NFTNotInBuyNowState,
+        NftNotInBuyNowState,
 
         /// Auction type is not `Open`
         IsNotOpenAuctionType,
@@ -184,8 +184,8 @@ decl_error! {
         /// Bid lock duration is not expired
         BidLockDurationIsNotExpired,
 
-        /// NFT auction is already expired
-        NFTAuctionIsAlreadyExpired,
+        /// Nft auction is already expired
+        NftAuctionIsAlreadyExpired,
 
         /// Auction buy now is less then starting price
         BuyNowIsLessThenStartingPrice,

+ 107 - 278
runtime-modules/content/src/lib.rs

@@ -2,7 +2,7 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 #![recursion_limit = "256"]
 // Internal Substrate warning (decl_event).
-#![allow(clippy::unused_unit, clippy::all)]
+#![allow(clippy::unused_unit)]
 
 #[cfg(test)]
 mod tests;
@@ -66,9 +66,6 @@ pub trait Trait:
     /// The overarching event type.
     type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
 
-    /// Channel Transfer Payments Escrow Account seed for ModuleId to compute deterministic AccountId
-    type ChannelOwnershipPaymentEscrowId: Get<[u8; 8]>;
-
     /// Type of identifier for Videos
     type VideoId: NumericIdentifier;
 
@@ -78,18 +75,6 @@ pub trait Trait:
     /// Type of identifier for Channel Categories
     type ChannelCategoryId: NumericIdentifier;
 
-    /// Type of identifier for Playlists
-    type PlaylistId: NumericIdentifier;
-
-    /// Type of identifier for Persons
-    type PersonId: NumericIdentifier;
-
-    /// Type of identifier for Channels
-    type SeriesId: NumericIdentifier;
-
-    /// Type of identifier for Channel transfer requests
-    type ChannelOwnershipTransferRequestId: NumericIdentifier;
-
     /// The maximum number of curators per group constraint
     type MaxNumberOfCuratorsPerGroup: Get<MaxNumber>;
 
@@ -111,7 +96,6 @@ pub trait Trait:
     /// Cleanup Margin used in bloat bond calculation
     type CleanupMargin: Get<<Self as balances::Trait>::Balance>;
 
-    // TODO: make it a function of the create_post extrinsic weights when weights will be established
     /// Cleanup Cost used in bloat bond calculation
     type CleanupCost: Get<<Self as balances::Trait>::Balance>;
 
@@ -140,14 +124,6 @@ decl_storage! {
         pub VideoCategoryById get(fn video_category_by_id):
         map hasher(blake2_128_concat) T::VideoCategoryId => VideoCategory;
 
-        pub PlaylistById get(fn playlist_by_id): map hasher(blake2_128_concat) T::PlaylistId => Playlist<T::ChannelId>;
-
-        pub SeriesById get(fn series_by_id):
-        map hasher(blake2_128_concat) T::SeriesId => Series<T::ChannelId, T::VideoId>;
-
-        pub PersonById get(fn person_by_id):
-        map hasher(blake2_128_concat) T::PersonId => Person<T::MemberId>;
-
         pub NextChannelCategoryId get(fn next_channel_category_id) config(): T::ChannelCategoryId;
 
         pub NextChannelId get(fn next_channel_id) config(): T::ChannelId;
@@ -156,15 +132,6 @@ decl_storage! {
 
         pub NextVideoId get(fn next_video_id) config(): T::VideoId;
 
-        pub NextPlaylistId get(fn next_playlist_id) config(): T::PlaylistId;
-
-        pub NextPersonId get(fn next_person_id) config(): T::PersonId;
-
-        pub NextSeriesId get(fn next_series_id) config(): T::SeriesId;
-
-        pub NextChannelOwnershipTransferRequestId get(fn next_channel_transfer_request_id) config():
-        T::ChannelOwnershipTransferRequestId;
-
         pub NextCuratorGroupId get(fn next_curator_group_id) config(): T::CuratorGroupId;
 
         pub CuratorGroupById get(fn curator_group_by_id):
@@ -411,7 +378,7 @@ decl_module! {
 
             let deletion_prize = storage::DynamicBagDeletionPrize::<T> {
                 prize: Zero::zero(), // put 0 for Giza release
-                account_id: sender.clone(),
+                account_id: sender,
             };
 
             if Storage::<T>::ensure_bag_exists(&channel_bag_id).is_err() {
@@ -450,7 +417,7 @@ decl_module! {
             }
 
             // this will not fail because can_create_dynamic_bag_with_objects_constraints will check also for successful upload conditions
-            if let Some(params) = upload_params.clone() {
+            if let Some(params) = upload_params{
                 Storage::<T>::upload_data_objects(params)?;
             }
 
@@ -474,7 +441,6 @@ decl_module! {
             Self::deposit_event(RawEvent::ChannelCreated(actor, channel_id, channel, params));
         }
 
-        // Include Option<AccountId> in ChannelUpdateParameters to update reward_account
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn update_channel(
             origin,
@@ -536,7 +502,7 @@ decl_module! {
                     &sender
                 );
 
-                Storage::<T>::upload_data_objects(params.clone())?;
+                Storage::<T>::upload_data_objects(params)?;
             }
 
             if !params.assets_to_remove.is_empty() {
@@ -614,7 +580,7 @@ decl_module! {
                     Storage::<T>::delete_data_objects(
                         sender.clone(),
                         Self::bag_id_for_channel(&channel_id),
-                        assets_to_remove.clone(),
+                        assets_to_remove,
                     )?;
                 }
 
@@ -731,7 +697,7 @@ decl_module! {
             channel_id: T::ChannelId,
             params: VideoCreationParameters<T>,
         ) {
-            let sender = ensure_signed(origin.clone())?;
+            let sender = ensure_signed(origin)?;
 
             // check that channel exists
             let channel = Self::ensure_channel_validity(&channel_id)?;
@@ -745,11 +711,6 @@ decl_module! {
             // next video id
             let video_id = NextVideoId::<T>::get();
 
-            //
-            // == MUTATION SAFE ==
-            //
-
-            // upload to storage: check is performed beforehand in the extrinsics so storage state won't be endangered
             if let Some(upload_assets) = params.assets.as_ref() {
                 let params = Self::construct_upload_parameters(
                     upload_assets,
@@ -759,17 +720,30 @@ decl_module! {
                 Storage::<T>::upload_data_objects(params)?;
             }
 
+            let nft_status = params.auto_issue_nft
+                .as_ref()
+                .map_or(
+                    Ok(None),
+                    |issuance_params| {
+                        Some(Self::construct_owned_nft(issuance_params)).transpose()
+                    }
+            )?;
+
             // create the video struct
             let video: Video<T> = VideoRecord {
                 in_channel: channel_id,
-                in_series: None,
                 is_censored: false,
                 enable_comments: params.enable_comments,
                 video_post_id:  None,
                 /// Newly created video has no nft
-                nft_status: None,
+                nft_status,
             };
 
+            //
+            // == MUTATION SAFE ==
+            //
+
+
             // add it to the onchain state
             VideoById::<T>::insert(video_id, video);
 
@@ -793,7 +767,7 @@ decl_module! {
             video_id: T::VideoId,
             params: VideoUpdateParameters<T>,
         ) {
-            let sender = ensure_signed(origin.clone())?;
+            let sender = ensure_signed(origin)?;
             // check that video exists, retrieve corresponding channel id.
             let video = Self::ensure_video_validity(&video_id)?;
 
@@ -854,7 +828,7 @@ decl_module! {
             video_id: T::VideoId,
             assets_to_remove: BTreeSet<DataObjectId<T>>,
         ) {
-            let sender = ensure_signed(origin.clone())?;
+            let sender = ensure_signed(origin)?;
 
             // check that video exists
             let video = Self::ensure_video_validity(&video_id)?;
@@ -869,9 +843,6 @@ decl_module! {
                 &channel,
             )?;
 
-            // ensure video can be removed
-            Self::ensure_video_can_be_removed(&video)?;
-
             // Ensure nft for this video have not been issued
             video.ensure_nft_is_not_issued::<T>()?;
 
@@ -882,16 +853,6 @@ decl_module! {
                 )?;
             }
 
-            // TODO: Solve #now
-            // If video is on storage, remove it
-            // if let Some(data_objects_id_set) = video.maybe_data_objects_id_set {
-            //     Storage::<T>::delete_data_objects(
-            //         channel.deletion_prize_source_account_id,
-            //         Self::bag_id_for_channel(&channel_id),
-            //         data_objects_id_set,
-            //     )?;
-            // }
-
             // bloat bond logic: channel owner is refunded
             video.video_post_id.as_ref().map(
                 |video_post_id| Self::video_deletion_refund_logic(&sender, &video_id, &video_post_id)
@@ -905,7 +866,7 @@ decl_module! {
                 Storage::<T>::delete_data_objects(
                     sender,
                     Self::bag_id_for_channel(&channel_id),
-                    assets_to_remove.clone()
+                    assets_to_remove,
                 )?;
             }
 
@@ -924,36 +885,6 @@ decl_module! {
             Self::deposit_event(RawEvent::VideoDeleted(actor, video_id));
         }
 
-        #[weight = 10_000_000] // TODO: adjust weight
-        pub fn create_playlist(
-            _origin,
-            _actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
-            _channel_id: T::ChannelId,
-            _params: PlaylistCreationParameters,
-        ) {
-            Self::not_implemented()?;
-        }
-
-        #[weight = 10_000_000] // TODO: adjust weight
-        pub fn update_playlist(
-            _origin,
-            _actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
-            _playlist: T::PlaylistId,
-            _params: PlaylistUpdateParameters,
-        ) {
-            Self::not_implemented()?;
-        }
-
-        #[weight = 10_000_000] // TODO: adjust weight
-        pub fn delete_playlist(
-            _origin,
-            _actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
-            _channel_id: T::ChannelId,
-            _playlist: T::PlaylistId,
-        ) {
-            Self::not_implemented()?;
-        }
-
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn set_featured_videos(
             origin,
@@ -1031,54 +962,6 @@ decl_module! {
 
             Self::deposit_event(RawEvent::VideoCategoryDeleted(actor, category_id));
         }
-
-        #[weight = 10_000_000] // TODO: adjust weight
-        pub fn create_person(
-            _origin,
-            _actor: PersonActor<T::MemberId, T::CuratorId>,
-            _params: PersonCreationParameters<StorageAssets<T>>,
-        ) {
-            Self::not_implemented()?;
-        }
-
-        #[weight = 10_000_000] // TODO: adjust weight
-        pub fn update_person(
-            _origin,
-            _actor: PersonActor<T::MemberId, T::CuratorId>,
-            _person: T::PersonId,
-            _params: PersonUpdateParameters<StorageAssets<T>>,
-        ) {
-            Self::not_implemented()?;
-        }
-
-        #[weight = 10_000_000] // TODO: adjust weight
-        pub fn delete_person(
-            _origin,
-            _actor: PersonActor<T::MemberId, T::CuratorId>,
-            _person: T::PersonId,
-        ) {
-            Self::not_implemented()?;
-        }
-
-        #[weight = 10_000_000] // TODO: adjust weight
-        pub fn add_person_to_video(
-            _origin,
-            _actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
-            _video_id: T::VideoId,
-            _person: T::PersonId
-        ) {
-            Self::not_implemented()?;
-        }
-
-        #[weight = 10_000_000] // TODO: adjust weight
-        pub fn remove_person_from_video(
-            _origin,
-            _actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
-            _video_id: T::VideoId
-        ) {
-            Self::not_implemented()?;
-        }
-
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn update_video_censorship_status(
             origin,
@@ -1120,35 +1003,6 @@ decl_module! {
             Ok(())
         }
 
-        #[weight = 10_000_000] // TODO: adjust weight
-        pub fn create_series(
-            _origin,
-            _actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
-            _channel_id: T::ChannelId,
-            _params: SeriesParameters<T::VideoId, StorageAssets<T>>
-        ) {
-            Self::not_implemented()?;
-        }
-
-        #[weight = 10_000_000] // TODO: adjust weight
-        pub fn update_series(
-            _origin,
-            _actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
-            _channel_id: T::ChannelId,
-            _params: SeriesParameters<T::VideoId, StorageAssets<T>>
-        ) {
-            Self::not_implemented()?;
-        }
-
-        #[weight = 10_000_000] // TODO: adjust weight
-        pub fn delete_series(
-            _origin,
-            _actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
-            _series: T::SeriesId,
-        ) {
-            Self::not_implemented()?;
-        }
-
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn create_post(
             origin,
@@ -1156,7 +1010,7 @@ decl_module! {
             params: VideoPostCreationParameters<T>,
         ) -> DispatchResult {
 
-            let sender = ensure_signed(origin.clone())?;
+            let sender = ensure_signed(origin)?;
 
             // ensure channel is valid
             let video = Self::ensure_video_validity(&params.video_reference)?;
@@ -1182,7 +1036,7 @@ decl_module! {
                 author: actor,
                 bloat_bond: initial_bloat_bond,
                 replies_count: T::VideoPostId::zero(),
-                video_reference: params.video_reference.clone(),
+                video_reference: params.video_reference,
                 post_type: params.post_type.clone(),
             };
 
@@ -1194,7 +1048,7 @@ decl_module! {
             // == MUTATION SAFE ==
             //
 
-            <ContentTreasury<T>>::deposit(&sender, initial_bloat_bond.clone())?;
+            <ContentTreasury<T>>::deposit(&sender, initial_bloat_bond)?;
 
             <NextVideoPostId<T>>::mutate(|x| *x = x.saturating_add(One::one()));
             <VideoPostById<T>>::insert(&params.video_reference, &post_id, post.clone());
@@ -1207,7 +1061,7 @@ decl_module! {
                     |x| x.replies_count = x.replies_count.saturating_add(One::one())),
                 VideoPostType::<T>::Description => VideoById::<T>::mutate(
                     &params.video_reference,
-                    |video| video.video_post_id = Some(post_id.clone())),
+                    |video| video.video_post_id = Some(post_id)),
             };
 
             // deposit event
@@ -1224,7 +1078,7 @@ decl_module! {
             actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
             new_text: Vec<u8>,
         ) {
-            let sender = ensure_signed(origin.clone())?;
+            let sender = ensure_signed(origin)?;
             let post = Self::ensure_post_exists(video_id, post_id)?;
             let video = VideoById::<T>::get(video_id);
             let channel = ChannelById::<T>::get(video.in_channel);
@@ -1254,7 +1108,7 @@ decl_module! {
             actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
             params: VideoPostDeletionParameters<T>,
         ) {
-            let sender = ensure_signed(origin.clone())?;
+            let sender = ensure_signed(origin)?;
             let post = Self::ensure_post_exists(video_id, post_id)?;
             let video = VideoById::<T>::get(video_id);
             let channel = ChannelById::<T>::get(video.in_channel);
@@ -1294,15 +1148,15 @@ decl_module! {
             // == MUTATION_SAFE ==
             //
 
-            Self::refund(&sender, cleanup_actor, post.bloat_bond.clone())?;
+            Self::refund(&sender, cleanup_actor, post.bloat_bond)?;
 
             match post.post_type {
                 VideoPostType::<T>::Comment(parent_id) => {
                     VideoPostById::<T>::remove(&video_id, &post_id);
                     // parent post might have been already deleted
                     if let Ok(mut parent_post) = Self::ensure_post_exists(
-                        video_id.clone(),
-                        parent_id.clone(),
+                        video_id,
+                        parent_id,
                     ){
                         parent_post.replies_count =
                             parent_post.replies_count.saturating_sub(T::VideoPostId::one());
@@ -1464,9 +1318,7 @@ decl_module! {
             origin,
             actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
             video_id: T::VideoId,
-            royalty: Option<Royalty>,
-            metadata: Metadata,
-            to: Option<T::MemberId>,
+            params: NftIssuanceParameters<T>
         ) {
 
             let sender = ensure_signed(origin)?;
@@ -1485,24 +1337,14 @@ decl_module! {
             ensure_actor_authorized_to_update_channel_assets::<T>(&sender, &actor, &channel)?;
 
             // The content owner will be..
-            let nft_owner = if let Some(to) = to {
-                NFTOwner::Member(to)
-            } else {
-                // if `to` set to None, actor issues to ChannelOwner
-                NFTOwner::ChannelOwner
-            };
-
-            // Enure royalty bounds satisfied, if provided
-            if let Some(royalty) = royalty {
-                Self::ensure_royalty_bounds_satisfied(royalty)?;
-            }
+            let nft_status = Self::construct_owned_nft(&params)?;
 
             //
             // == MUTATION SAFE ==
             //
 
-            // Issue NFT
-            let video = video.set_nft_status(OwnedNFT::new(nft_owner, royalty));
+            // Issue Nft
+            let video = video.set_nft_status(nft_status);
 
             // Update the video
             VideoById::<T>::insert(video_id, video);
@@ -1510,9 +1352,10 @@ decl_module! {
             Self::deposit_event(RawEvent::NftIssued(
                 actor,
                 video_id,
-                royalty,
-                metadata,
-                to,
+                params.royalty,
+                params.nft_metadata,
+                params.non_channel_owner,
+                params.init_transactional_status
             ));
         }
 
@@ -1597,7 +1440,7 @@ decl_module! {
             Self::deposit_event(RawEvent::AuctionCanceled(owner_id, video_id));
         }
 
-        /// Cancel NFT offer
+        /// Cancel Nft offer
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn cancel_offer(
             origin,
@@ -1630,7 +1473,7 @@ decl_module! {
             Self::deposit_event(RawEvent::OfferCanceled(video_id, owner_id));
         }
 
-        /// Cancel NFT sell order
+        /// Cancel Nft sell order
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn cancel_buy_now(
             origin,
@@ -1877,7 +1720,7 @@ decl_module! {
             Self::deposit_event(RawEvent::OpenAuctionBidAccepted(owner_id, video_id));
         }
 
-        /// Offer NFT
+        /// Offer Nft
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn offer_nft(
             origin,
@@ -1913,7 +1756,7 @@ decl_module! {
             Self::deposit_event(RawEvent::OfferStarted(video_id, owner_id, to, price));
         }
 
-        /// Return NFT back to the original artist at no cost
+        /// Return Nft back to the original artist at no cost
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn sling_nft_back(
             origin,
@@ -1938,7 +1781,7 @@ decl_module! {
             //
 
             // Set nft owner to ChannelOwner
-            let nft = nft.set_owner(NFTOwner::ChannelOwner);
+            let nft = nft.set_owner(NftOwner::ChannelOwner);
             let video = video.set_nft_status(nft);
 
             VideoById::<T>::insert(video_id, video);
@@ -1947,7 +1790,7 @@ decl_module! {
             Self::deposit_event(RawEvent::NftSlingedBackToTheOriginalArtist(video_id, owner_id));
         }
 
-        /// Accept incoming NFT offer
+        /// Accept incoming Nft offer
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn accept_incoming_offer(
             origin,
@@ -1980,7 +1823,7 @@ decl_module! {
             Self::deposit_event(RawEvent::OfferAccepted(video_id));
         }
 
-        /// Sell NFT
+        /// Sell Nft
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn sell_nft(
             origin,
@@ -2012,10 +1855,10 @@ decl_module! {
             VideoById::<T>::insert(video_id, video);
 
             // Trigger event
-            Self::deposit_event(RawEvent::NFTSellOrderMade(video_id, owner_id, price));
+            Self::deposit_event(RawEvent::NftSellOrderMade(video_id, owner_id, price));
         }
 
-        /// Buy NFT
+        /// Buy Nft
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn buy_nft(
             origin,
@@ -2049,7 +1892,7 @@ decl_module! {
             VideoById::<T>::insert(video_id, video);
 
             // Trigger event
-            Self::deposit_event(RawEvent::NFTBought(video_id, participant_id));
+            Self::deposit_event(RawEvent::NftBought(video_id, participant_id));
         }
     }
 }
@@ -2129,7 +1972,7 @@ impl<T: Trait> Module<T> {
 
         let channel_migration_done = current_id == final_id;
 
-        return video_migration_done && channel_migration_done;
+        video_migration_done && channel_migration_done
     }
 
     /// Ensure `CuratorGroup` under given id exists
@@ -2175,12 +2018,6 @@ impl<T: Trait> Module<T> {
         Ok(VideoById::<T>::get(video_id))
     }
 
-    // Ensure given video is not in season
-    fn ensure_video_can_be_removed(video: &Video<T>) -> DispatchResult {
-        ensure!(video.in_series.is_none(), Error::<T>::VideoInSeason);
-        Ok(())
-    }
-
     fn ensure_channel_category_exists(
         channel_category_id: &T::ChannelCategoryId,
     ) -> Result<ChannelCategory, Error<T>> {
@@ -2212,10 +2049,6 @@ impl<T: Trait> Module<T> {
         Ok(VideoPostById::<T>::get(video_id, post_id))
     }
 
-    fn not_implemented() -> DispatchResult {
-        Err(Error::<T>::FeatureNotImplemented.into())
-    }
-
     fn refund(
         sender: &<T as frame_system::Trait>::AccountId,
         cleanup_actor: CleanupActor,
@@ -2241,11 +2074,11 @@ impl<T: Trait> Module<T> {
     }
 
     /// Ensure owner account id exists, retreive corresponding one.
-    pub fn ensure_owner_account_id(
+    fn ensure_owner_account_id(
         video: &Video<T>,
         owned_nft: &Nft<T>,
     ) -> Result<T::AccountId, Error<T>> {
-        if let NFTOwner::Member(member_id) = owned_nft.owner {
+        if let NftOwner::Member(member_id) = owned_nft.owner {
             let membership = <membership::Module<T>>::ensure_membership(member_id)
                 .map_err(|_| Error::<T>::MemberProfileNotFound)?;
             Ok(membership.controller_account)
@@ -2256,6 +2089,53 @@ impl<T: Trait> Module<T> {
         }
     }
 
+    /// Convert InitTransactionalStatus to TransactionalStatus after checking requirements on the Auction variant
+    fn ensure_valid_init_transactional_status(
+        init_status: &InitTransactionalStatus<T>,
+    ) -> Result<TransactionalStatus<T>, DispatchError> {
+        match init_status {
+            InitTransactionalStatus::<T>::Idle => Ok(TransactionalStatus::<T>::Idle),
+            InitTransactionalStatus::<T>::InitiatedOfferToMember(member, balance) => Ok(
+                TransactionalStatus::<T>::InitiatedOfferToMember(*member, *balance),
+            ),
+            InitTransactionalStatus::<T>::Auction(params) => {
+                Self::validate_auction_params(&params)?;
+                let mut auction = AuctionRecord::new(params.clone());
+                if params.starts_at.is_none() {
+                    auction.starts_at = <frame_system::Module<T>>::block_number();
+                }
+                Ok(TransactionalStatus::<T>::Auction(auction))
+            }
+        }
+    }
+
+    /// Construct the Nft that is intended to be issued
+    pub fn construct_owned_nft(
+        issuance_params: &NftIssuanceParameters<T>,
+    ) -> Result<Nft<T>, DispatchError> {
+        let transactional_status = Self::ensure_valid_init_transactional_status(
+            &issuance_params.init_transactional_status,
+        )?;
+        // The content owner will be..
+        let nft_owner = if let Some(to) = issuance_params.non_channel_owner {
+            NftOwner::Member(to)
+        } else {
+            // if `to` set to None, actor issues to ChannelOwner
+            NftOwner::ChannelOwner
+        };
+
+        // Enure royalty bounds satisfied, if provided
+        if let Some(royalty) = issuance_params.royalty.as_ref() {
+            Self::ensure_royalty_bounds_satisfied(*royalty)?;
+        }
+
+        Ok(Nft::<T>::new(
+            nft_owner,
+            issuance_params.royalty,
+            transactional_status,
+        ))
+    }
+
     fn bag_id_for_channel(channel_id: &T::ChannelId) -> storage::BagId<T> {
         // retrieve bag id from channel id
         let dyn_bag = DynamicBagIdType::<T::MemberId, T::ChannelId>::Channel(*channel_id);
@@ -2356,12 +2236,6 @@ decl_event!(
         VideoCategoryId = <T as Trait>::VideoCategoryId,
         ChannelId = <T as storage::Trait>::ChannelId,
         ChannelCategoryId = <T as Trait>::ChannelCategoryId,
-        ChannelOwnershipTransferRequestId = <T as Trait>::ChannelOwnershipTransferRequestId,
-        PlaylistId = <T as Trait>::PlaylistId,
-        SeriesId = <T as Trait>::SeriesId,
-        PersonId = <T as Trait>::PersonId,
-        ChannelOwnershipTransferRequest = ChannelOwnershipTransferRequest<T>,
-        Series = Series<<T as storage::Trait>::ChannelId, <T as Trait>::VideoId>,
         Channel = Channel<T>,
         DataObjectId = DataObjectId<T>,
         IsCensored = bool,
@@ -2370,13 +2244,13 @@ decl_event!(
             CurrencyOf<T>,
             <T as common::MembershipTypes>::MemberId,
         >,
+        InitTransactionalStatus = InitTransactionalStatus<T>,
         Balance = BalanceOf<T>,
         CurrencyAmount = CurrencyOf<T>,
         ChannelCreationParameters = ChannelCreationParameters<T>,
         ChannelUpdateParameters = ChannelUpdateParameters<T>,
         VideoCreationParameters = VideoCreationParameters<T>,
         VideoUpdateParameters = VideoUpdateParameters<T>,
-        StorageAssets = StorageAssets<T>,
         VideoPost = VideoPost<T>,
         VideoPostId = <T as Trait>::VideoPostId,
         ReactionId = <T as Trait>::ReactionId,
@@ -2394,6 +2268,7 @@ decl_event!(
         ChannelCreated(ContentActor, ChannelId, Channel, ChannelCreationParameters),
         ChannelUpdated(ContentActor, ChannelId, Channel, ChannelUpdateParameters),
         ChannelAssetsRemoved(ContentActor, ChannelId, BTreeSet<DataObjectId>, Channel),
+        ChannelDeleted(ContentActor, ChannelId),
 
         ChannelCensorshipStatusUpdated(
             ContentActor,
@@ -2402,15 +2277,6 @@ decl_event!(
             Vec<u8>, /* rationale */
         ),
 
-        // Channel Ownership Transfers
-        ChannelOwnershipTransferRequested(
-            ContentActor,
-            ChannelOwnershipTransferRequestId,
-            ChannelOwnershipTransferRequest,
-        ),
-        ChannelOwnershipTransferRequestWithdrawn(ContentActor, ChannelOwnershipTransferRequestId),
-        ChannelOwnershipTransferred(ContentActor, ChannelOwnershipTransferRequestId),
-
         // Channel Categories
         ChannelCategoryCreated(
             ChannelCategoryId,
@@ -2447,44 +2313,6 @@ decl_event!(
         // Featured Videos
         FeaturedVideosSet(ContentActor, Vec<VideoId>),
 
-        // Video Playlists
-        PlaylistCreated(ContentActor, PlaylistId, PlaylistCreationParameters),
-        PlaylistUpdated(ContentActor, PlaylistId, PlaylistUpdateParameters),
-        PlaylistDeleted(ContentActor, PlaylistId),
-
-        // Series
-        SeriesCreated(
-            ContentActor,
-            SeriesId,
-            StorageAssets,
-            SeriesParameters<VideoId, StorageAssets>,
-            Series,
-        ),
-        SeriesUpdated(
-            ContentActor,
-            SeriesId,
-            StorageAssets,
-            SeriesParameters<VideoId, StorageAssets>,
-            Series,
-        ),
-        SeriesDeleted(ContentActor, SeriesId),
-
-        // Persons
-        PersonCreated(
-            ContentActor,
-            PersonId,
-            StorageAssets,
-            PersonCreationParameters<StorageAssets>,
-        ),
-        PersonUpdated(
-            ContentActor,
-            PersonId,
-            StorageAssets,
-            PersonUpdateParameters<StorageAssets>,
-        ),
-        PersonDeleted(ContentActor, PersonId),
-        ChannelDeleted(ContentActor, ChannelId),
-
         // VideoPosts & Replies
         VideoPostCreated(VideoPost, VideoPostId),
         VideoPostTextUpdated(ContentActor, Vec<u8>, VideoPostId, VideoId),
@@ -2498,7 +2326,7 @@ decl_event!(
         ChannelRewardUpdated(Balance, ChannelId),
         MaxRewardUpdated(Balance),
         MinCashoutUpdated(Balance),
-        // NFT auction
+        // Nft auction
         AuctionStarted(ContentActor, VideoId, AuctionParams),
         NftIssued(
             ContentActor,
@@ -2506,6 +2334,7 @@ decl_event!(
             Option<Royalty>,
             Metadata,
             Option<MemberId>,
+            InitTransactionalStatus,
         ),
         AuctionBidMade(MemberId, VideoId, CurrencyAmount, IsExtended),
         AuctionBidCanceled(MemberId, VideoId),
@@ -2516,8 +2345,8 @@ decl_event!(
         OfferStarted(VideoId, ContentActor, MemberId, Option<CurrencyAmount>),
         OfferAccepted(VideoId),
         OfferCanceled(VideoId, ContentActor),
-        NFTSellOrderMade(VideoId, ContentActor, CurrencyAmount),
-        NFTBought(VideoId, MemberId),
+        NftSellOrderMade(VideoId, ContentActor, CurrencyAmount),
+        NftBought(VideoId, MemberId),
         BuyNowCanceled(VideoId, ContentActor),
         NftSlingedBackToTheOriginalArtist(VideoId, ContentActor),
     }

+ 16 - 16
runtime-modules/content/src/nft/mod.rs

@@ -221,10 +221,10 @@ impl<T: Trait> Module<T> {
         nft: &Nft<T>,
         participant_account_id: &T::AccountId,
     ) -> DispatchResult {
-        if let TransactionalStatus::BuyNow(price) = &nft.transactional_status {
+        if let TransactionalStatus::<T>::BuyNow(price) = &nft.transactional_status {
             Self::ensure_sufficient_free_balance(participant_account_id, *price)
         } else {
-            Err(Error::<T>::NFTNotInBuyNowState.into())
+            Err(Error::<T>::NftNotInBuyNowState.into())
         }
     }
 
@@ -233,7 +233,7 @@ impl<T: Trait> Module<T> {
         nft: &Nft<T>,
         participant_account_id: &T::AccountId,
     ) -> DispatchResult {
-        if let TransactionalStatus::InitiatedOfferToMember(member_id, price) =
+        if let TransactionalStatus::<T>::InitiatedOfferToMember(member_id, price) =
             &nft.transactional_status
         {
             // Authorize participant under given member id
@@ -248,9 +248,9 @@ impl<T: Trait> Module<T> {
         }
     }
 
-    /// Cancel NFT transaction
+    /// Cancel Nft transaction
     pub fn cancel_transaction(nft: Nft<T>) -> Nft<T> {
-        if let TransactionalStatus::Auction(ref auction) = nft.transactional_status {
+        if let TransactionalStatus::<T>::Auction(ref auction) = nft.transactional_status {
             if let Some(ref last_bid) = auction.last_bid {
                 // Unreserve previous bidder balance
                 T::Currency::unreserve(&last_bid.bidder_account_id, last_bid.amount);
@@ -268,7 +268,7 @@ impl<T: Trait> Module<T> {
         new_owner_account_id: T::AccountId,
         new_owner: T::MemberId,
     ) -> Nft<T> {
-        if let TransactionalStatus::BuyNow(price) = &nft.transactional_status {
+        if let TransactionalStatus::<T>::BuyNow(price) = &nft.transactional_status {
             Self::complete_payment(
                 in_channel,
                 nft.creator_royalty,
@@ -278,7 +278,7 @@ impl<T: Trait> Module<T> {
                 false,
             );
 
-            nft.owner = NFTOwner::Member(new_owner);
+            nft.owner = NftOwner::Member(new_owner);
         }
 
         nft.set_idle_transactional_status()
@@ -291,7 +291,9 @@ impl<T: Trait> Module<T> {
         owner_account_id: T::AccountId,
         new_owner_account_id: T::AccountId,
     ) -> Nft<T> {
-        if let TransactionalStatus::InitiatedOfferToMember(to, price) = &nft.transactional_status {
+        if let TransactionalStatus::<T>::InitiatedOfferToMember(to, price) =
+            &nft.transactional_status
+        {
             if let Some(price) = price {
                 Self::complete_payment(
                     in_channel,
@@ -303,7 +305,7 @@ impl<T: Trait> Module<T> {
                 );
             }
 
-            nft.owner = NFTOwner::Member(*to);
+            nft.owner = NftOwner::Member(*to);
         }
 
         nft.set_idle_transactional_status()
@@ -350,11 +352,9 @@ impl<T: Trait> Module<T> {
                 // Deposit royalty into creator account
                 T::Currency::deposit_creating(&creator_account_id, royalty);
             }
-        } else {
-            if let Some(receiver_account_id) = receiver_account_id {
-                // Deposit amount, exluding auction fee into receiver account
-                T::Currency::deposit_creating(&receiver_account_id, amount - auction_fee);
-            }
+        } else if let Some(receiver_account_id) = receiver_account_id {
+            // Deposit amount, exluding auction fee into receiver account
+            T::Currency::deposit_creating(&receiver_account_id, amount - auction_fee);
         }
     }
 
@@ -378,8 +378,8 @@ impl<T: Trait> Module<T> {
             true,
         );
 
-        nft.owner = NFTOwner::Member(last_bidder);
-        nft.transactional_status = TransactionalStatus::Idle;
+        nft.owner = NftOwner::Member(last_bidder);
+        nft.transactional_status = TransactionalStatus::<T>::Idle;
         nft
     }
 }

+ 92 - 29
runtime-modules/content/src/nft/types.rs

@@ -1,15 +1,15 @@
 use super::*;
 
-/// Metadata for NFT issuance
+/// Metadata for Nft issuance
 pub type Metadata = Vec<u8>;
 
 /// Owner royalty
 pub type Royalty = Perbill;
 
-/// NFT transactional status
+/// Nft transactional status
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
-pub enum TransactionalStatus<
+pub enum TransactionalStatusRecord<
     BlockNumber: BaseArithmetic + Copy + Default,
     MemberId: Default + Copy + Ord,
     AccountId: Default + Clone + Ord,
@@ -26,24 +26,31 @@ impl<
         MemberId: Default + Copy + Ord,
         AccountId: Default + Clone + Ord,
         Balance: Default + Clone + BaseArithmetic,
-    > Default for TransactionalStatus<BlockNumber, MemberId, AccountId, Balance>
+    > Default for TransactionalStatusRecord<BlockNumber, MemberId, AccountId, Balance>
 {
     fn default() -> Self {
         Self::Idle
     }
 }
 
-/// Owned NFT representation
+pub type TransactionalStatus<T> = TransactionalStatusRecord<
+    <T as frame_system::Trait>::BlockNumber,
+    <T as common::MembershipTypes>::MemberId,
+    <T as frame_system::Trait>::AccountId,
+    CurrencyOf<T>,
+>;
+
+/// Owned Nft representation
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
-pub struct OwnedNFT<
+pub struct OwnedNft<
     BlockNumber: BaseArithmetic + Copy + Default,
     MemberId: Default + Copy + Ord,
     AccountId: Default + Clone + Ord,
     Balance: Default + Clone + BaseArithmetic,
 > {
-    pub owner: NFTOwner<MemberId>,
-    pub transactional_status: TransactionalStatus<BlockNumber, MemberId, AccountId, Balance>,
+    pub owner: NftOwner<MemberId>,
+    pub transactional_status: TransactionalStatusRecord<BlockNumber, MemberId, AccountId, Balance>,
     pub creator_royalty: Option<Royalty>,
 }
 
@@ -52,19 +59,23 @@ impl<
         MemberId: Default + Copy + PartialEq + Ord,
         AccountId: Default + Clone + PartialEq + Ord,
         Balance: Default + Clone + BaseArithmetic,
-    > OwnedNFT<BlockNumber, MemberId, AccountId, Balance>
+    > OwnedNft<BlockNumber, MemberId, AccountId, Balance>
 {
-    /// Create new NFT
-    pub fn new(owner: NFTOwner<MemberId>, creator_royalty: Option<Royalty>) -> Self {
+    /// Create new Nft
+    pub fn new(
+        owner: NftOwner<MemberId>,
+        creator_royalty: Option<Royalty>,
+        transactional_status: TransactionalStatusRecord<BlockNumber, MemberId, AccountId, Balance>,
+    ) -> Self {
         Self {
             owner,
-            transactional_status: TransactionalStatus::Idle,
+            transactional_status,
             creator_royalty,
         }
     }
 
     /// Set nft owner
-    pub fn set_owner(mut self, owner: NFTOwner<MemberId>) -> Self {
+    pub fn set_owner(mut self, owner: NftOwner<MemberId>) -> Self {
         self.owner = owner;
         self
     }
@@ -73,7 +84,7 @@ impl<
     pub fn ensure_auction_state<T: Trait>(
         &self,
     ) -> Result<AuctionRecord<BlockNumber, Balance, MemberId, AccountId>, Error<T>> {
-        if let TransactionalStatus::Auction(auction) = &self.transactional_status {
+        if let TransactionalStatusRecord::Auction(auction) = &self.transactional_status {
             Ok(auction.to_owned())
         } else {
             Err(Error::<T>::NotInAuctionState)
@@ -82,7 +93,7 @@ impl<
 
     ///  Ensure nft transactional status is set to `Idle`
     pub fn ensure_nft_transactional_status_is_idle<T: Trait>(&self) -> DispatchResult {
-        if let TransactionalStatus::Idle = self.transactional_status {
+        if let TransactionalStatusRecord::Idle = self.transactional_status {
             Ok(())
         } else {
             Err(Error::<T>::NftIsNotIdle.into())
@@ -91,7 +102,7 @@ impl<
 
     /// Sets nft transactional status to `BuyNow`
     pub fn set_buy_now_transactionl_status(mut self, buy_now_price: Balance) -> Self {
-        self.transactional_status = TransactionalStatus::BuyNow(buy_now_price);
+        self.transactional_status = TransactionalStatusRecord::BuyNow(buy_now_price);
         self
     }
 
@@ -100,13 +111,13 @@ impl<
         mut self,
         auction: AuctionRecord<BlockNumber, Balance, MemberId, AccountId>,
     ) -> Self {
-        self.transactional_status = TransactionalStatus::Auction(auction);
+        self.transactional_status = TransactionalStatusRecord::Auction(auction);
         self
     }
 
     /// Set nft transactional status to `Idle`
     pub fn set_idle_transactional_status(mut self) -> Self {
-        self.transactional_status = TransactionalStatus::Idle;
+        self.transactional_status = TransactionalStatusRecord::Idle;
         self
     }
 
@@ -116,27 +127,30 @@ impl<
         to: MemberId,
         balance: Option<Balance>,
     ) -> Self {
-        self.transactional_status = TransactionalStatus::InitiatedOfferToMember(to, balance);
+        self.transactional_status = TransactionalStatusRecord::InitiatedOfferToMember(to, balance);
         self
     }
 
-    /// Ensure NFT has pending offer
+    /// Ensure Nft has pending offer
     pub fn ensure_pending_offer_state<T: Trait>(&self) -> DispatchResult {
         ensure!(
             matches!(
                 self.transactional_status,
-                TransactionalStatus::InitiatedOfferToMember(..),
+                TransactionalStatusRecord::InitiatedOfferToMember(..),
             ),
             Error::<T>::PendingOfferDoesNotExist
         );
         Ok(())
     }
 
-    /// Ensure NFT is in BuyNow state
+    /// Ensure Nft is in BuyNow state
     pub fn ensure_buy_now_state<T: Trait>(&self) -> DispatchResult {
         ensure!(
-            matches!(self.transactional_status, TransactionalStatus::BuyNow(..),),
-            Error::<T>::NFTNotInBuyNowState
+            matches!(
+                self.transactional_status,
+                TransactionalStatusRecord::BuyNow(..),
+            ),
+            Error::<T>::NftNotInBuyNowState
         );
         Ok(())
     }
@@ -144,12 +158,12 @@ impl<
 
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
-pub enum NFTOwner<MemberId> {
+pub enum NftOwner<MemberId> {
     ChannelOwner,
     Member(MemberId),
 }
 
-impl<MemberId> Default for NFTOwner<MemberId> {
+impl<MemberId> Default for NftOwner<MemberId> {
     fn default() -> Self {
         Self::ChannelOwner
     }
@@ -339,7 +353,7 @@ impl<
     ) -> DispatchResult {
         ensure!(
             !self.is_nft_auction_expired(current_block),
-            Error::<T>::NFTAuctionIsAlreadyExpired
+            Error::<T>::NftAuctionIsAlreadyExpired
         );
         Ok(())
     }
@@ -438,8 +452,8 @@ pub type Auction<T> = AuctionRecord<
     <T as frame_system::Trait>::AccountId,
 >;
 
-/// OwnedNFT alias type for simplification.
-pub type Nft<T> = OwnedNFT<
+/// OwnedNft alias type for simplification.
+pub type Nft<T> = OwnedNft<
     <T as frame_system::Trait>::BlockNumber,
     <T as common::MembershipTypes>::MemberId,
     <T as frame_system::Trait>::AccountId,
@@ -493,3 +507,52 @@ pub struct OpenAuctionDetails<BlockNumber> {
     // bid lock duration
     pub bid_lock_duration: BlockNumber,
 }
+
+/// Parameters used to issue a nft
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
+pub struct NftIssuanceParametersRecord<MemberId, InitTransactionalStatus> {
+    /// Roayalty used for the author
+    pub royalty: Option<Royalty>,
+    /// Metadata
+    pub nft_metadata: Metadata,
+    /// member id Nft will be issued to
+    pub non_channel_owner: Option<MemberId>,
+    /// Initial transactional status for the nft
+    pub init_transactional_status: InitTransactionalStatus,
+}
+
+pub type NftIssuanceParameters<T> = NftIssuanceParametersRecord<
+    <T as common::MembershipTypes>::MemberId,
+    InitTransactionalStatus<T>,
+>;
+
+/// Initial Transactional status for the Nft: See InitialTransactionalStatusRecord above
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
+pub enum InitTransactionalStatusRecord<
+    BlockNumber: BaseArithmetic + Copy + Default,
+    MemberId: Default + Copy + Ord,
+    Balance: Default + Clone + BaseArithmetic,
+> {
+    Idle,
+    InitiatedOfferToMember(MemberId, Option<Balance>),
+    Auction(AuctionParams<BlockNumber, Balance, MemberId>),
+}
+
+impl<
+        BlockNumber: BaseArithmetic + Copy + Default,
+        MemberId: Default + Copy + Ord,
+        Balance: Default + Clone + BaseArithmetic,
+    > Default for InitTransactionalStatusRecord<BlockNumber, MemberId, Balance>
+{
+    fn default() -> Self {
+        Self::Idle
+    }
+}
+
+pub type InitTransactionalStatus<T> = InitTransactionalStatusRecord<
+    <T as frame_system::Trait>::BlockNumber,
+    <T as common::MembershipTypes>::MemberId,
+    CurrencyOf<T>,
+>;

+ 2 - 2
runtime-modules/content/src/permissions/mod.rs

@@ -257,13 +257,13 @@ pub fn ensure_actor_is_channel_owner<T: Trait>(
 pub fn ensure_actor_authorized_to_manage_nft<T: Trait>(
     origin: T::Origin,
     actor: &ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
-    nft_owner: &NFTOwner<T::MemberId>,
+    nft_owner: &NftOwner<T::MemberId>,
     in_channel: T::ChannelId,
 ) -> DispatchResult {
     let sender = ensure_signed(origin)?;
     ensure_actor_auth_success::<T>(&sender, actor)?;
 
-    if let NFTOwner::Member(member_id) = nft_owner {
+    if let NftOwner::Member(member_id) = nft_owner {
         ensure!(
             *actor == ContentActor::Member(*member_id),
             Error::<T>::ActorNotAuthorized

+ 1 - 0
runtime-modules/content/src/tests/fixtures.rs

@@ -174,6 +174,7 @@ impl CreateVideoFixture {
                 assets: None,
                 meta: None,
                 enable_comments: true,
+                auto_issue_nft: None,
             },
             channel_id: ChannelId::one(), // channel index starts at 1
         }

+ 1 - 0
runtime-modules/content/src/tests/migration.rs

@@ -8,6 +8,7 @@ fn assert_video_and_channel_existrinsics_with(result: DispatchResult) {
         assets: None,
         meta: None,
         enable_comments: true,
+        auto_issue_nft: None,
     };
 
     // attempt to create valid channel if result is ok, otherwise id does not matter

+ 1 - 28
runtime-modules/content/src/tests/mock.rs

@@ -1,6 +1,6 @@
 #![cfg(test)]
 use crate::*;
-use frame_support::dispatch::{DispatchError, DispatchResult};
+use frame_support::dispatch::DispatchResult;
 use frame_support::traits::{LockIdentifier, OnFinalize, OnInitialize};
 use frame_support::{impl_outer_event, impl_outer_origin, parameter_types};
 pub use membership::WeightInfo;
@@ -407,9 +407,6 @@ impl Trait for Test {
     /// The overarching event type.
     type Event = MetaEvent;
 
-    /// Channel Transfer Payments Escrow Account seed for ModuleId to compute deterministic AccountId
-    type ChannelOwnershipPaymentEscrowId = ChannelOwnershipPaymentEscrowId;
-
     /// Type of identifier for Videos
     type VideoId = u64;
 
@@ -419,18 +416,6 @@ impl Trait for Test {
     /// Type of identifier for Channel Categories
     type ChannelCategoryId = u64;
 
-    /// Type of identifier for Playlists
-    type PlaylistId = u64;
-
-    /// Type of identifier for Persons
-    type PersonId = u64;
-
-    /// Type of identifier for Channels
-    type SeriesId = u64;
-
-    /// Type of identifier for Channel transfer requests
-    type ChannelOwnershipTransferRequestId = u64;
-
     /// The maximum number of curators per group constraint
     type MaxNumberOfCuratorsPerGroup = MaxNumberOfCuratorsPerGroup;
 
@@ -472,10 +457,6 @@ pub struct ExtBuilder {
     next_channel_id: u64,
     next_video_category_id: u64,
     next_video_id: u64,
-    next_playlist_id: u64,
-    next_person_id: u64,
-    next_series_id: u64,
-    next_channel_transfer_request_id: u64,
     next_curator_group_id: u64,
     next_video_post_id: u64,
     video_migration: VideoMigrationConfig<Test>,
@@ -507,10 +488,6 @@ impl Default for ExtBuilder {
             next_channel_id: 1,
             next_video_category_id: 1,
             next_video_id: 1,
-            next_playlist_id: 1,
-            next_person_id: 1,
-            next_series_id: 1,
-            next_channel_transfer_request_id: 1,
             next_curator_group_id: 1,
             next_video_post_id: 1,
             video_migration: MigrationConfigRecord {
@@ -554,10 +531,6 @@ impl ExtBuilder {
             next_channel_id: self.next_channel_id,
             next_video_category_id: self.next_video_category_id,
             next_video_id: self.next_video_id,
-            next_playlist_id: self.next_playlist_id,
-            next_person_id: self.next_person_id,
-            next_series_id: self.next_series_id,
-            next_channel_transfer_request_id: self.next_channel_transfer_request_id,
             next_curator_group_id: self.next_curator_group_id,
             next_video_post_id: self.next_video_post_id,
             video_migration: self.video_migration,

+ 1 - 1
runtime-modules/content/src/tests/nft.rs

@@ -1,4 +1,4 @@
-//mod accept_incoming_offer;
+mod accept_incoming_offer;
 mod buy_nft;
 mod cancel_buy_now;
 mod cancel_nft_auction;

+ 69 - 90
runtime-modules/content/src/tests/nft/accept_incoming_offer.rs

@@ -1,5 +1,8 @@
 #![cfg(test)]
-
+use crate::tests::fixtures::{
+    create_default_member_owned_channel_with_video, create_initial_storage_buckets_helper,
+    increase_account_balance_helper, UpdateChannelFixture,
+};
 use crate::tests::mock::*;
 use crate::*;
 use frame_support::{assert_err, assert_ok};
@@ -11,24 +14,23 @@ fn accept_incoming_offer() {
         run_to_block(1);
 
         let video_id = NextVideoId::<Test>::get();
-
-        create_simple_channel_and_video(FIRST_MEMBER_ORIGIN, FIRST_MEMBER_ID);
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel_with_video();
 
         // Issue nft
         assert_ok!(Content::issue_nft(
-            Origin::signed(FIRST_MEMBER_ORIGIN),
-            ContentActor::Member(FIRST_MEMBER_ID),
+            Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
+            ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Offer nft
         assert_ok!(Content::offer_nft(
-            Origin::signed(FIRST_MEMBER_ORIGIN),
+            Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             video_id,
-            ContentActor::Member(FIRST_MEMBER_ID),
+            ContentActor::Member(DEFAULT_MEMBER_ID),
             SECOND_MEMBER_ID,
             None,
         ));
@@ -40,7 +42,7 @@ fn accept_incoming_offer() {
 
         // Accept nft offer
         assert_ok!(Content::accept_incoming_offer(
-            Origin::signed(SECOND_MEMBER_ORIGIN),
+            Origin::signed(SECOND_MEMBER_ACCOUNT_ID),
             video_id,
         ));
 
@@ -49,17 +51,18 @@ fn accept_incoming_offer() {
         // Ensure nft offer accepted succesfully
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                owner: NFTOwner::Member(member_id),
-                transactional_status: TransactionalStatus::Idle,
+            Some(OwnedNft {
+                owner: NftOwner::Member(member_id),
+                transactional_status: TransactionalStatus::<Test>::Idle,
                 ..
             }) if member_id == SECOND_MEMBER_ID
         ));
 
-        let offer_accepted_event = get_test_event(RawEvent::OfferAccepted(video_id));
-
         // Last event checked
-        assert_event(offer_accepted_event, number_of_events_before_call + 1);
+        assert_event(
+            MetaEvent::content(RawEvent::OfferAccepted(video_id)),
+            number_of_events_before_call + 1,
+        );
     })
 }
 
@@ -73,7 +76,7 @@ fn accept_incoming_offer_video_does_not_exist() {
 
         // Make an attempt to accept incoming nft offer if corresponding video does not exist
         let accept_incoming_offer_result =
-            Content::accept_incoming_offer(Origin::signed(SECOND_MEMBER_ORIGIN), video_id);
+            Content::accept_incoming_offer(Origin::signed(SECOND_MEMBER_ACCOUNT_ID), video_id);
 
         // Failure checked
         assert_err!(
@@ -90,15 +93,16 @@ fn accept_incoming_offer_nft_not_issued() {
         run_to_block(1);
 
         let video_id = NextVideoId::<Test>::get();
-
-        create_simple_channel_and_video(FIRST_MEMBER_ORIGIN, FIRST_MEMBER_ID);
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel_with_video();
 
         // Make an attempt to accept incoming nft offer if corresponding nft is not issued yet
         let accept_incoming_offer_result =
-            Content::accept_incoming_offer(Origin::signed(SECOND_MEMBER_ORIGIN), video_id);
+            Content::accept_incoming_offer(Origin::signed(SECOND_MEMBER_ACCOUNT_ID), video_id);
 
         // Failure checked
-        assert_err!(accept_incoming_offer_result, Error::<Test>::NFTDoesNotExist);
+        assert_err!(accept_incoming_offer_result, Error::<Test>::NftDoesNotExist);
     })
 }
 
@@ -109,31 +113,32 @@ fn accept_incoming_offer_auth_failed() {
         run_to_block(1);
 
         let video_id = NextVideoId::<Test>::get();
-
-        create_simple_channel_and_video(FIRST_MEMBER_ORIGIN, FIRST_MEMBER_ID);
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel_with_video();
 
         // Issue nft
         assert_ok!(Content::issue_nft(
-            Origin::signed(FIRST_MEMBER_ORIGIN),
-            ContentActor::Member(FIRST_MEMBER_ID),
+            Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
+            ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Offer nft
         assert_ok!(Content::offer_nft(
-            Origin::signed(FIRST_MEMBER_ORIGIN),
+            Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             video_id,
-            ContentActor::Member(FIRST_MEMBER_ID),
+            ContentActor::Member(DEFAULT_MEMBER_ID),
             SECOND_MEMBER_ID,
             None,
         ));
 
         // Make an attempt to accept incoming nft offer providing wrong credentials
-        let accept_incoming_offer_result =
-            Content::accept_incoming_offer(Origin::signed(UNKNOWN_ORIGIN), video_id);
+        let accept_incoming_offer_result = Content::accept_incoming_offer(
+            Origin::signed(UNAUTHORIZED_MEMBER_ACCOUNT_ID),
+            video_id,
+        );
 
         // Failure checked
         assert_err!(
@@ -150,22 +155,21 @@ fn accept_incoming_offer_no_incoming_offers() {
         run_to_block(1);
 
         let video_id = NextVideoId::<Test>::get();
-
-        create_simple_channel_and_video(FIRST_MEMBER_ORIGIN, FIRST_MEMBER_ID);
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel_with_video();
 
         // Issue nft
         assert_ok!(Content::issue_nft(
-            Origin::signed(FIRST_MEMBER_ORIGIN),
-            ContentActor::Member(FIRST_MEMBER_ID),
+            Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
+            ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to accept incoming nft offer if there is no incoming transfers
         let accept_incoming_offer_result =
-            Content::accept_incoming_offer(Origin::signed(SECOND_MEMBER_ORIGIN), video_id);
+            Content::accept_incoming_offer(Origin::signed(SECOND_MEMBER_ACCOUNT_ID), video_id);
 
         // Failure checked
         assert_err!(
@@ -182,58 +186,36 @@ fn accept_incoming_offer_reward_account_is_not_set() {
         run_to_block(1);
 
         let video_id = NextVideoId::<Test>::get();
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel_with_video();
 
-        let _ = balances::Module::<Test>::deposit_creating(
-            &FIRST_MEMBER_ORIGIN,
-            <Test as balances::Trait>::Balance::from(100u32),
-        );
-
-        let channel_id = NextChannelId::<Test>::get();
-
-        create_channel_mock(
-            FIRST_MEMBER_ORIGIN,
-            ContentActor::Member(FIRST_MEMBER_ID),
-            ChannelCreationParametersRecord {
-                assets: NewAssets::<Test>::Urls(vec![]),
-                meta: vec![],
-                reward_account: None,
-            },
-            Ok(()),
-        );
-
-        let params = get_video_creation_parameters();
-
-        // Create simple video using member actor
-        create_video_mock(
-            FIRST_MEMBER_ORIGIN,
-            ContentActor::Member(FIRST_MEMBER_ID),
-            channel_id,
-            params,
-            Ok(()),
-        );
+        UpdateChannelFixture::default()
+            .with_sender(DEFAULT_MEMBER_ACCOUNT_ID)
+            .with_actor(ContentActor::Member(DEFAULT_MEMBER_ID))
+            .with_reward_account(Some(None))
+            .call_and_assert(Ok(()));
 
         // Issue nft
         assert_ok!(Content::issue_nft(
-            Origin::signed(FIRST_MEMBER_ORIGIN),
-            ContentActor::Member(FIRST_MEMBER_ID),
+            Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
+            ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Offer nft
         assert_ok!(Content::offer_nft(
-            Origin::signed(FIRST_MEMBER_ORIGIN),
+            Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             video_id,
-            ContentActor::Member(FIRST_MEMBER_ID),
+            ContentActor::Member(DEFAULT_MEMBER_ID),
             SECOND_MEMBER_ID,
             None,
         ));
 
         // Make an attempt to accept incoming nft offer if sender is owner and reward account is not set
         let accept_incoming_offer_result =
-            Content::accept_incoming_offer(Origin::signed(SECOND_MEMBER_ORIGIN), video_id);
+            Content::accept_incoming_offer(Origin::signed(SECOND_MEMBER_ACCOUNT_ID), video_id);
 
         // Failure checked
         assert_err!(
@@ -250,33 +232,30 @@ fn accept_incoming_offer_insufficient_balance() {
         run_to_block(1);
 
         let video_id = NextVideoId::<Test>::get();
-
-        create_simple_channel_and_video(FIRST_MEMBER_ORIGIN, FIRST_MEMBER_ID);
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel_with_video();
 
         // Issue nft
         assert_ok!(Content::issue_nft(
-            Origin::signed(FIRST_MEMBER_ORIGIN),
-            ContentActor::Member(FIRST_MEMBER_ID),
+            Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
+            ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
-        let price = 10000;
-
         // Offer nft
         assert_ok!(Content::offer_nft(
-            Origin::signed(FIRST_MEMBER_ORIGIN),
+            Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             video_id,
-            ContentActor::Member(FIRST_MEMBER_ID),
+            ContentActor::Member(DEFAULT_MEMBER_ID),
             SECOND_MEMBER_ID,
-            Some(price),
+            Some(DEFAULT_NFT_PRICE),
         ));
 
         // Make an attempt to accept incoming nft offer if there is no incoming transfers
         let accept_incoming_offer_result =
-            Content::accept_incoming_offer(Origin::signed(SECOND_MEMBER_ORIGIN), video_id);
+            Content::accept_incoming_offer(Origin::signed(SECOND_MEMBER_ACCOUNT_ID), video_id);
 
         // Failure checked
         assert_err!(

+ 11 - 21
runtime-modules/content/src/tests/nft/buy_nft.rs

@@ -26,9 +26,7 @@ fn buy_nft() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // deposit balance to second member
@@ -74,16 +72,16 @@ fn buy_nft() {
         // Ensure nft succesfully bought
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                owner: NFTOwner::Member(SECOND_MEMBER_ID),
-                transactional_status: TransactionalStatus::Idle,
+            Some(OwnedNft {
+                owner: NftOwner::Member(SECOND_MEMBER_ID),
+                transactional_status: TransactionalStatus::<Test>::Idle,
                 ..
             })
         ));
 
         // Last event checked
         assert_event(
-            MetaEvent::content(RawEvent::NFTBought(video_id, SECOND_MEMBER_ID)),
+            MetaEvent::content(RawEvent::NftBought(video_id, SECOND_MEMBER_ID)),
             number_of_events_before_call + 1,
         );
     })
@@ -136,7 +134,7 @@ fn buy_nft_not_issued() {
         );
 
         // Failure checked
-        assert_err!(buy_nft_result, Error::<Test>::NFTDoesNotExist);
+        assert_err!(buy_nft_result, Error::<Test>::NftDoesNotExist);
     })
 }
 
@@ -158,9 +156,7 @@ fn buy_nft_auth_failed() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Sell nft
@@ -200,9 +196,7 @@ fn buy_nft_not_in_buy_now_state() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to buy nft which is not in BuyNow state
@@ -213,7 +207,7 @@ fn buy_nft_not_in_buy_now_state() {
         );
 
         // Failure checked
-        assert_err!(buy_nft_result, Error::<Test>::NFTNotInBuyNowState);
+        assert_err!(buy_nft_result, Error::<Test>::NftNotInBuyNowState);
     })
 }
 
@@ -233,9 +227,7 @@ fn buy_nft_insufficient_balance() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Sell nft
@@ -281,9 +273,7 @@ fn buy_nft_reward_account_is_not_set() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // deposit balance to second member

+ 8 - 16
runtime-modules/content/src/tests/nft/cancel_buy_now.rs

@@ -24,9 +24,7 @@ fn cancel_buy_now() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         increase_account_balance_helper(SECOND_MEMBER_ACCOUNT_ID, DEFAULT_NFT_PRICE);
@@ -56,8 +54,8 @@ fn cancel_buy_now() {
         // Ensure nft status changed to given Auction
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                transactional_status: TransactionalStatus::Idle,
+            Some(OwnedNft {
+                transactional_status: TransactionalStatus::<Test>::Idle,
                 ..
             })
         ));
@@ -113,7 +111,7 @@ fn cancel_buy_now_not_issued() {
         );
 
         // Failure checked
-        assert_err!(cancel_buy_now_result, Error::<Test>::NFTDoesNotExist);
+        assert_err!(cancel_buy_now_result, Error::<Test>::NftDoesNotExist);
     })
 }
 
@@ -134,9 +132,7 @@ fn cancel_buy_now_auth_failed() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Sell nft
@@ -176,9 +172,7 @@ fn cancel_buy_now_not_authorized() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Sell nft
@@ -218,9 +212,7 @@ fn cancel_buy_now_not_in_auction_state() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to cancel buy now if there is no pending one
@@ -231,6 +223,6 @@ fn cancel_buy_now_not_in_auction_state() {
         );
 
         // Failure checked
-        assert_err!(cancel_buy_now_result, Error::<Test>::NFTNotInBuyNowState);
+        assert_err!(cancel_buy_now_result, Error::<Test>::NftNotInBuyNowState);
     })
 }

+ 8 - 18
runtime-modules/content/src/tests/nft/cancel_nft_auction.rs

@@ -24,9 +24,7 @@ fn cancel_nft_auction() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Start nft auction
@@ -54,8 +52,8 @@ fn cancel_nft_auction() {
         // Ensure nft status changed to given Auction
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                transactional_status: TransactionalStatus::Idle,
+            Some(OwnedNft {
+                transactional_status: TransactionalStatus::<Test>::Idle,
                 ..
             })
         ));
@@ -111,7 +109,7 @@ fn cancel_nft_auction_not_issued() {
         );
 
         // Failure checked
-        assert_err!(cancel_nft_auction_result, Error::<Test>::NFTDoesNotExist);
+        assert_err!(cancel_nft_auction_result, Error::<Test>::NftDoesNotExist);
     })
 }
 
@@ -132,9 +130,7 @@ fn cancel_nft_auction_auth_failed() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Start nft auction
@@ -174,9 +170,7 @@ fn cancel_nft_auction_not_authorized() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Start nft auction
@@ -216,9 +210,7 @@ fn cancel_nft_auction_not_in_auction_state() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to cancel nft auction if there is no pending one
@@ -250,9 +242,7 @@ fn cancel_nft_auction_english_auction_with_bids() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = AuctionParams {

+ 7 - 15
runtime-modules/content/src/tests/nft/cancel_offer.rs

@@ -24,9 +24,7 @@ fn cancel_offer() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Offer nft
@@ -55,8 +53,8 @@ fn cancel_offer() {
         // Ensure nft status changed to given Auction
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                transactional_status: TransactionalStatus::Idle,
+            Some(OwnedNft {
+                transactional_status: TransactionalStatus::<Test>::Idle,
                 ..
             })
         ));
@@ -112,7 +110,7 @@ fn cancel_offer_not_issued() {
         );
 
         // Failure checked
-        assert_err!(cancel_offer_result, Error::<Test>::NFTDoesNotExist);
+        assert_err!(cancel_offer_result, Error::<Test>::NftDoesNotExist);
     })
 }
 
@@ -133,9 +131,7 @@ fn cancel_offer_auth_failed() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Offer nft
@@ -176,9 +172,7 @@ fn cancel_offer_not_authorized() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Offer nft
@@ -219,9 +213,7 @@ fn cancel_offer_not_in_auction_state() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to cancel offer if there is no pending one

+ 10 - 24
runtime-modules/content/src/tests/nft/cancel_open_auction_bid.rs

@@ -24,9 +24,7 @@ fn cancel_open_auction_bid() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let bid_lock_duration = Content::min_bid_lock_duration();
@@ -81,8 +79,8 @@ fn cancel_open_auction_bid() {
         // Ensure bid on specific auction successfully canceled
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                transactional_status: TransactionalStatus::Auction(auction_without_bid,),
+            Some(OwnedNft {
+                transactional_status: TransactionalStatus::<Test>::Auction(auction_without_bid,),
                 ..
             }) if auction_without_bid.last_bid.is_none()
         ));
@@ -112,9 +110,7 @@ fn cancel_open_auction_bid_lock_duration_did_not_expire() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let bid_lock_duration = Content::min_bid_lock_duration();
@@ -181,9 +177,7 @@ fn cancel_open_auction_bid_auth_failed() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let bid_lock_duration = Content::min_bid_lock_duration();
@@ -281,7 +275,7 @@ fn cancel_open_auction_bid_nft_is_not_issued() {
         // Failure checked
         assert_err!(
             cancel_open_auction_bid_result,
-            Error::<Test>::NFTDoesNotExist
+            Error::<Test>::NftDoesNotExist
         );
     })
 }
@@ -303,9 +297,7 @@ fn cancel_open_auction_bid_not_in_auction_state() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to cancel open auction bid for nft which is not in auction state
@@ -340,9 +332,7 @@ fn cancel_open_auction_bid_is_not_open_auction_type() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = AuctionParams {
@@ -410,9 +400,7 @@ fn cancel_open_auction_bid_last_bid_does_not_exist() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let bid_lock_duration = Content::min_bid_lock_duration();
@@ -469,9 +457,7 @@ fn cancel_open_auction_bid_actor_is_not_a_last_bidder() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let bid_lock_duration = Content::min_bid_lock_duration();

+ 9 - 21
runtime-modules/content/src/tests/nft/claim_won_english_auction.rs

@@ -24,9 +24,7 @@ fn claim_won_english_auction() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = AuctionParams {
@@ -82,8 +80,8 @@ fn claim_won_english_auction() {
         // Ensure english auction successfully completed
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                transactional_status: TransactionalStatus::Idle,
+            Some(OwnedNft {
+                transactional_status: TransactionalStatus::<Test>::Idle,
                 ..
             })
         ));
@@ -116,9 +114,7 @@ fn claim_won_english_auction_cannot_be_completed() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = AuctionParams {
@@ -186,9 +182,7 @@ fn claim_won_english_auction_auth_failed() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = AuctionParams {
@@ -287,7 +281,7 @@ fn claim_won_english_auction_nft_is_not_issued() {
         // Failure checked
         assert_err!(
             claim_won_english_auction_result,
-            Error::<Test>::NFTDoesNotExist
+            Error::<Test>::NftDoesNotExist
         );
     })
 }
@@ -309,9 +303,7 @@ fn claim_won_english_auction_not_in_auction_state() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to claim won english auction for nft which is not in auction state
@@ -346,9 +338,7 @@ fn claim_won_english_auction_is_not_english_auction_type() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let bid_lock_duration = Content::min_bid_lock_duration();
@@ -415,9 +405,7 @@ fn claim_won_english_auction_last_bid_does_not_exist() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = AuctionParams {

+ 67 - 29
runtime-modules/content/src/tests/nft/issue_nft.rs

@@ -32,25 +32,29 @@ fn issue_nft() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Runtime tested state after call
 
         // Ensure nft created succesfully
-        let nft_status = Some(OwnedNFT::new(NFTOwner::ChannelOwner, None));
+        let nft_status = Some(OwnedNft::new(
+            NftOwner::ChannelOwner,
+            None,
+            TransactionalStatus::<Test>::Idle,
+        ));
         assert_eq!(nft_status, Content::video_by_id(video_id).nft_status);
 
         // Last event checked
+        let nft_issue_params = NftIssuanceParameters::<Test>::default();
         assert_event(
             MetaEvent::content(RawEvent::NftIssued(
                 ContentActor::Member(DEFAULT_MEMBER_ID),
                 video_id,
-                None,
-                b"metablob".to_vec(),
-                None,
+                nft_issue_params.royalty,
+                nft_issue_params.nft_metadata,
+                nft_issue_params.non_channel_owner,
+                nft_issue_params.init_transactional_status,
             )),
             number_of_events_before_call + 1,
         );
@@ -70,9 +74,7 @@ fn issue_nft_video_does_not_exist() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None,
+            NftIssuanceParameters::<Test>::default(),
         );
 
         // Failure checked
@@ -97,9 +99,7 @@ fn issue_nft_already_issued() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to issue nft once again for the same video
@@ -107,13 +107,11 @@ fn issue_nft_already_issued() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None,
+            NftIssuanceParameters::<Test>::default(),
         );
 
         // Failure checked
-        assert_err!(issue_nft_result, Error::<Test>::NFTAlreadyExists);
+        assert_err!(issue_nft_result, Error::<Test>::NftAlreadyExists);
     })
 }
 
@@ -134,9 +132,7 @@ fn issue_nft_auth_failed() {
             Origin::signed(UNAUTHORIZED_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None,
+            NftIssuanceParameters::<Test>::default(),
         );
 
         // Failure checked
@@ -161,9 +157,7 @@ fn issue_nft_actor_not_authorized() {
             Origin::signed(UNAUTHORIZED_MEMBER_ACCOUNT_ID),
             ContentActor::Member(UNAUTHORIZED_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None,
+            NftIssuanceParameters::<Test>::default(),
         );
 
         // Failure checked
@@ -188,9 +182,10 @@ fn issue_nft_royalty_bounds_violated() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            Some(Perbill::one()),
-            b"metablob".to_vec(),
-            None,
+            NftIssuanceParameters::<Test> {
+                royalty: Some(Perbill::one()),
+                ..NftIssuanceParameters::<Test>::default()
+            },
         );
 
         // Failure checked
@@ -201,12 +196,55 @@ fn issue_nft_royalty_bounds_violated() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            Some(Perbill::from_perthousand(1)),
-            b"metablob".to_vec(),
-            None,
+            NftIssuanceParameters::<Test> {
+                royalty: Some(Perbill::from_perthousand(1)),
+                ..NftIssuanceParameters::<Test>::default()
+            },
         );
 
         // Failure checked
         assert_err!(issue_nft_result, Error::<Test>::RoyaltyLowerBoundExceeded);
     })
 }
+
+#[test]
+fn issue_nft_fails_with_invalid_auction_parameters() {
+    with_default_mock_builder(|| {
+        // Run to block one to see emitted events
+        run_to_block(1);
+
+        let video_id = NextVideoId::<Test>::get();
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel_with_video();
+
+        let auction_params = AuctionParams {
+            starting_price: Content::min_starting_price() - 1,
+            buy_now_price: None,
+            auction_type: AuctionType::Open(OpenAuctionDetails {
+                bid_lock_duration: Content::min_bid_lock_duration(),
+            }),
+            minimal_bid_step: Content::min_bid_step(),
+            starts_at: None,
+            whitelist: BTreeSet::new(),
+        };
+
+        // Make an attempt to issue nft with wrong credentials
+        let issue_nft_result = Content::issue_nft(
+            Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
+            ContentActor::Member(DEFAULT_MEMBER_ID),
+            video_id,
+            NftIssuanceParameters::<Test> {
+                init_transactional_status: InitTransactionalStatus::<Test>::Auction(auction_params),
+                ..NftIssuanceParameters::<Test>::default()
+            },
+        );
+
+        // Failure checked
+        assert_err!(
+            issue_nft_result,
+            Error::<Test>::StartingPriceLowerBoundExceeded
+        );
+    })
+}

+ 17 - 37
runtime-modules/content/src/tests/nft/make_bid.rs

@@ -25,9 +25,7 @@ fn make_bid() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = get_open_auction_params();
@@ -77,8 +75,8 @@ fn make_bid() {
         // Ensure nft status changed to given Auction
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                transactional_status: TransactionalStatus::Auction(auction_with_bid,),
+            Some(OwnedNft {
+                transactional_status: TransactionalStatus::<Test>::Auction(auction_with_bid,),
                 ..
             }) if auction == auction_with_bid
         ));
@@ -113,9 +111,7 @@ fn make_bid_completes_auction() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let buy_now_price = Content::min_starting_price();
@@ -162,11 +158,11 @@ fn make_bid_completes_auction() {
         // Ensure nft status changed to given Auction
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                transactional_status: TransactionalStatus::Idle,
+            Some(OwnedNft {
+                transactional_status: TransactionalStatus::<Test>::Idle,
                 owner,
                 ..
-            }) if owner == NFTOwner::Member(SECOND_MEMBER_ID)
+            }) if owner == NftOwner::Member(SECOND_MEMBER_ID)
         ));
 
         // Last event checked
@@ -197,9 +193,7 @@ fn make_bid_auth_failed() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = get_open_auction_params();
@@ -247,9 +241,7 @@ fn make_bid_insufficient_balance() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = get_open_auction_params();
@@ -329,7 +321,7 @@ fn make_bid_nft_is_not_issued() {
         );
 
         // Failure checked
-        assert_err!(make_bid_result, Error::<Test>::NFTDoesNotExist);
+        assert_err!(make_bid_result, Error::<Test>::NftDoesNotExist);
     })
 }
 
@@ -350,9 +342,7 @@ fn make_bid_nft_is_not_in_auction_state() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // deposit initial balance
@@ -390,9 +380,7 @@ fn make_bid_nft_auction_expired() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = AuctionParams {
@@ -432,7 +420,7 @@ fn make_bid_nft_auction_expired() {
         );
 
         // Failure checked
-        assert_err!(make_bid_result, Error::<Test>::NFTAuctionIsAlreadyExpired);
+        assert_err!(make_bid_result, Error::<Test>::NftAuctionIsAlreadyExpired);
     })
 }
 
@@ -453,9 +441,7 @@ fn make_bid_nft_auction_is_not_started() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let starting_price = Content::min_starting_price();
@@ -512,9 +498,7 @@ fn make_bid_member_is_not_allowed_to_participate() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = AuctionParams {
@@ -579,9 +563,7 @@ fn make_bid_starting_price_constraint_violated() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = AuctionParams {
@@ -640,9 +622,7 @@ fn make_bid_bid_step_constraint_violated() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = AuctionParams {

+ 7 - 15
runtime-modules/content/src/tests/nft/offer_nft.rs

@@ -24,9 +24,7 @@ fn offer_nft() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Runtime tested state before call
@@ -48,8 +46,8 @@ fn offer_nft() {
         // Ensure nft offered succesfully
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                transactional_status: TransactionalStatus::InitiatedOfferToMember(
+            Some(OwnedNft {
+                transactional_status: TransactionalStatus::<Test>::InitiatedOfferToMember(
                     SECOND_MEMBER_ID,
                     None
                 ),
@@ -114,7 +112,7 @@ fn offer_nft_not_issued() {
         );
 
         // Failure checked
-        assert_err!(offer_nft_result, Error::<Test>::NFTDoesNotExist);
+        assert_err!(offer_nft_result, Error::<Test>::NftDoesNotExist);
     })
 }
 
@@ -135,9 +133,7 @@ fn offer_nft_auth_failed() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to offer nft with wrong credentials
@@ -171,9 +167,7 @@ fn offer_nft_not_authorized() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to offer nft if actor is not authorized
@@ -207,9 +201,7 @@ fn offer_nft_transactional_status_is_not_idle() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Offer nft

+ 9 - 21
runtime-modules/content/src/tests/nft/pick_open_auction_winner.rs

@@ -24,9 +24,7 @@ fn pick_open_auction_winner() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let bid_lock_duration = Content::min_bid_lock_duration();
@@ -78,8 +76,8 @@ fn pick_open_auction_winner() {
         // Ensure english auction successfully completed
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                transactional_status: TransactionalStatus::Idle,
+            Some(OwnedNft {
+                transactional_status: TransactionalStatus::<Test>::Idle,
                 ..
             })
         ));
@@ -112,9 +110,7 @@ fn pick_open_auction_winner_auth_failed() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let bid_lock_duration = Content::min_bid_lock_duration();
@@ -184,9 +180,7 @@ fn pick_open_auction_winner_actor_not_authorized() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let bid_lock_duration = Content::min_bid_lock_duration();
@@ -284,7 +278,7 @@ fn pick_open_auction_winner_nft_is_not_issued() {
         // Failure checked
         assert_err!(
             pick_open_auction_winner_result,
-            Error::<Test>::NFTDoesNotExist
+            Error::<Test>::NftDoesNotExist
         );
     })
 }
@@ -306,9 +300,7 @@ fn pick_open_auction_winner_not_in_auction_state() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to pick open auction winner for nft which is not in auction state
@@ -343,9 +335,7 @@ fn pick_open_auction_winner_is_not_open_auction_type() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = AuctionParams {
@@ -413,9 +403,7 @@ fn pick_open_auction_winner_last_bid_does_not_exist() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let bid_lock_duration = Content::min_bid_lock_duration();

+ 8 - 16
runtime-modules/content/src/tests/nft/sell_nft.rs

@@ -24,9 +24,7 @@ fn sell_nft() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Runtime tested state before call
@@ -47,8 +45,8 @@ fn sell_nft() {
         // Ensure nft offer made succesfully
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                transactional_status: TransactionalStatus::BuyNow(
+            Some(OwnedNft {
+                transactional_status: TransactionalStatus::<Test>::BuyNow(
                     cost,
                 ),
                 ..
@@ -57,7 +55,7 @@ fn sell_nft() {
 
         // Last event checked
         assert_event(
-            MetaEvent::content(RawEvent::NFTSellOrderMade(
+            MetaEvent::content(RawEvent::NftSellOrderMade(
                 video_id,
                 ContentActor::Member(DEFAULT_MEMBER_ID),
                 DEFAULT_NFT_PRICE,
@@ -109,7 +107,7 @@ fn sell_nft_not_issued() {
         );
 
         // Failure checked
-        assert_err!(sell_nft_result, Error::<Test>::NFTDoesNotExist);
+        assert_err!(sell_nft_result, Error::<Test>::NftDoesNotExist);
     })
 }
 
@@ -130,9 +128,7 @@ fn sell_nft_auth_failed() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to sell nft with wrong credentials
@@ -165,9 +161,7 @@ fn sell_nft_not_authorized() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to sell nft if actor is not authorized
@@ -200,9 +194,7 @@ fn sell_nft_transactional_status_is_not_idle() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Offer nft

+ 12 - 17
runtime-modules/content/src/tests/nft/sling_nft_back.rs

@@ -24,16 +24,17 @@ fn sling_nft_back() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            Some(SECOND_MEMBER_ID),
+            NftIssuanceParameters::<Test> {
+                non_channel_owner: Some(SECOND_MEMBER_ID),
+                ..NftIssuanceParameters::<Test>::default()
+            }
         ));
 
         // Runtime tested state before call
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                owner: NFTOwner::Member(SECOND_MEMBER_ID),
+            Some(OwnedNft {
+                owner: NftOwner::Member(SECOND_MEMBER_ID),
                 ..
             })
         ));
@@ -53,8 +54,8 @@ fn sling_nft_back() {
         // Ensure nft slinged back successfully
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                owner: NFTOwner::ChannelOwner,
+            Some(OwnedNft {
+                owner: NftOwner::ChannelOwner,
                 ..
             })
         ));
@@ -110,7 +111,7 @@ fn sling_nft_back_not_issued() {
         );
 
         // Failure checked
-        assert_err!(sling_nft_back_result, Error::<Test>::NFTDoesNotExist);
+        assert_err!(sling_nft_back_result, Error::<Test>::NftDoesNotExist);
     })
 }
 
@@ -131,9 +132,7 @@ fn sling_nft_back_auth_failed() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to sling nft back with wrong credentials
@@ -165,9 +164,7 @@ fn sling_nft_back_not_authorized() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to sling nft back if actor is not authorized
@@ -199,9 +196,7 @@ fn sling_nft_back_transactional_status_is_not_idle() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Offer nft

+ 8 - 18
runtime-modules/content/src/tests/nft/start_nft_auction.rs

@@ -25,9 +25,7 @@ fn start_nft_auction() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Runtime tested state before call
@@ -56,8 +54,8 @@ fn start_nft_auction() {
         // Ensure nft status changed to given Auction
         assert!(matches!(
             Content::video_by_id(video_id).nft_status,
-            Some(OwnedNFT {
-                transactional_status: TransactionalStatus::Auction(created_auction,),
+            Some(OwnedNft {
+                transactional_status: TransactionalStatus::<Test>::Auction(created_auction,),
                 ..
             }) if auction == created_auction
         ));
@@ -120,7 +118,7 @@ fn start_nft_auction_not_issued() {
         );
 
         // Failure checked
-        assert_err!(start_nft_auction_result, Error::<Test>::NFTDoesNotExist);
+        assert_err!(start_nft_auction_result, Error::<Test>::NftDoesNotExist);
     })
 }
 
@@ -141,9 +139,7 @@ fn start_nft_auction_auth_failed() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = get_open_auction_params();
@@ -178,9 +174,7 @@ fn start_nft_auction_not_authorized() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         let auction_params = get_open_auction_params();
@@ -215,9 +209,7 @@ fn start_nft_auction_transactional_status_is_not_idle() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Offer nft
@@ -261,9 +253,7 @@ fn start_nft_auction_invalid_params() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to start nft auction if starting price provided is less then min starting price

+ 2 - 4
runtime-modules/content/src/tests/videos.rs

@@ -21,9 +21,7 @@ fn delete_video_nft_is_issued() {
             Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
             ContentActor::Member(DEFAULT_MEMBER_ID),
             video_id,
-            None,
-            b"metablob".to_vec(),
-            None
+            NftIssuanceParameters::<Test>::default(),
         ));
 
         // Make an attempt to delete a video, which has an nft issued already.
@@ -34,7 +32,7 @@ fn delete_video_nft_is_issued() {
                 video_id,
                 BTreeSet::new(),
             ),
-            Error::<Test>::NFTAlreadyExists
+            Error::<Test>::NftAlreadyExists
         );
     })
 }

+ 17 - 153
runtime-modules/content/src/types.rs

@@ -221,16 +221,19 @@ pub type StorageAssets<T> = StorageAssetsRecord<BalanceOf<T>>;
 /// Information about the video being created.
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
-pub struct VideoCreationParametersRecord<StorageAssets> {
+pub struct VideoCreationParametersRecord<StorageAssets, NftIssuanceParameters> {
     /// Asset collection for the video
     pub assets: Option<StorageAssets>,
     /// Metadata for the video.
     pub meta: Option<Vec<u8>>,
     /// Comments enabled or not
     pub enable_comments: bool,
+    /// Parameters for issuing video Nft
+    pub auto_issue_nft: Option<NftIssuanceParameters>,
 }
 
-pub type VideoCreationParameters<T> = VideoCreationParametersRecord<StorageAssets<T>>;
+pub type VideoCreationParameters<T> =
+    VideoCreationParametersRecord<StorageAssets<T>, NftIssuanceParameters<T>>;
 
 /// Information about the video being updated
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
@@ -251,9 +254,9 @@ pub type VideoUpdateParameters<T> = VideoUpdateParametersRecord<StorageAssets<T>
 /// A video which belongs to a channel. A video may be part of a series or playlist.
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
-pub struct VideoRecord<ChannelId, SeriesId, VideoPostId, OwnedNFT> {
+pub struct VideoRecord<ChannelId, VideoPostId, OwnedNft> {
+    /// channel the video is in
     pub in_channel: ChannelId,
-    pub in_series: Option<SeriesId>,
     /// Whether the curators have censored the video or not.
     pub is_censored: bool,
     /// enable or not comments
@@ -261,149 +264,11 @@ pub struct VideoRecord<ChannelId, SeriesId, VideoPostId, OwnedNFT> {
     /// First post to a video works as a description
     pub video_post_id: Option<VideoPostId>,
     /// Whether nft for this video have been issued.
-    pub nft_status: Option<OwnedNFT>,
+    pub nft_status: Option<OwnedNft>,
 }
 
-pub type Video<T> = VideoRecord<
-    <T as storage::Trait>::ChannelId,
-    <T as Trait>::SeriesId,
-    <T as Trait>::VideoPostId,
-    Nft<T>,
->;
-
-/// Information about the plyalist being created.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
-pub struct PlaylistCreationParameters {
-    /// Metadata about the playlist.
-    meta: Vec<u8>,
-}
-
-/// Information about the playlist being updated.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
-pub struct PlaylistUpdateParameters {
-    // It is the only field so its not an Option
-    /// Metadata update for the playlist.
-    new_meta: Vec<u8>,
-}
-
-/// A playlist is an ordered collection of videos.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
-pub struct Playlist<ChannelId> {
-    /// The channel the playlist belongs to.
-    in_channel: ChannelId,
-}
-
-/// Information about the episode being created or updated.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
-pub enum EpisodeParameters<VideoId, StorageAssets> {
-    /// A new video is being added as the episode.
-    NewVideo(VideoCreationParametersRecord<StorageAssets>),
-    /// An existing video is being made into an episode.
-    ExistingVideo(VideoId),
-}
-
-/// Information about the season being created or updated.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
-pub struct SeasonParameters<VideoId, StorageAssets> {
-    /// Season assets referenced by metadata
-    assets: Option<StorageAssets>,
-    // ?? It might just be more straighforward to always provide full list of episodes at cost of larger tx.
-    /// If set, updates the episodes of a season. Extends the number of episodes in a season
-    /// when length of new_episodes is greater than previously set. Last elements must all be
-    /// 'Some' in that case.
-    /// Will truncate existing season when length of new_episodes is less than previously set.
-    episodes: Option<Vec<Option<EpisodeParameters<VideoId, StorageAssets>>>>,
-
-    meta: Option<Vec<u8>>,
-}
-
-/// Information about the series being created or updated.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
-pub struct SeriesParameters<VideoId, StorageAssets> {
-    /// Series assets referenced by metadata
-    assets: Option<StorageAssets>,
-    // ?? It might just be more straighforward to always provide full list of seasons at cost of larger tx.
-    /// If set, updates the seasons of a series. Extend a series when length of seasons is
-    /// greater than previoulsy set. Last elements must all be 'Some' in that case.
-    /// Will truncate existing series when length of seasons is less than previously set.
-    seasons: Option<Vec<Option<SeasonParameters<VideoId, StorageAssets>>>>,
-    meta: Option<Vec<u8>>,
-}
-
-/// A season is an ordered list of videos (episodes).
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
-pub struct Season<VideoId> {
-    episodes: Vec<VideoId>,
-}
-
-/// A series is an ordered list of seasons that belongs to a channel.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
-pub struct Series<ChannelId, VideoId> {
-    in_channel: ChannelId,
-    seasons: Vec<Season<VideoId>>,
-}
-
-/// The actor the caller/origin is trying to act as for Person creation and update and delete calls.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
-pub enum PersonActor<MemberId, CuratorId> {
-    Member(MemberId),
-    Curator(CuratorId),
-}
-
-/// The authorized actor that may update or delete a Person.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
-pub enum PersonController<MemberId> {
-    /// Member controls the person
-    Member(MemberId),
-    /// Any curator controls the person
-    Curators,
-}
-
-/// Default trait implemented only because its used in Person which needs to implement a Default trait
-/// since it is a StorageValue.
-impl<MemberId: Default> Default for PersonController<MemberId> {
-    fn default() -> Self {
-        PersonController::Member(MemberId::default())
-    }
-}
-
-/// Information for Person being created.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
-pub struct PersonCreationParameters<StorageAssets> {
-    /// Assets referenced by metadata
-    assets: StorageAssets,
-    /// Metadata for person.
-    meta: Vec<u8>,
-}
-
-/// Information for Persion being updated.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
-pub struct PersonUpdateParameters<StorageAssets> {
-    /// Assets referenced by metadata
-    assets: Option<StorageAssets>,
-    /// Metadata to update person.
-    new_meta: Option<Vec<u8>>,
-}
-
-/// A Person represents a real person that may be associated with a video.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
-pub struct Person<MemberId> {
-    /// Who can update or delete this person.
-    controlled_by: PersonController<MemberId>,
-}
+pub type Video<T> =
+    VideoRecord<<T as storage::Trait>::ChannelId, <T as Trait>::VideoPostId, Nft<T>>;
 
 pub type DataObjectId<T> = <T as storage::Trait>::DataObjectId;
 
@@ -541,26 +406,26 @@ pub type PullPayment<T> = PullPaymentElement<
     <T as frame_system::Trait>::Hash,
 >;
 
-impl<ChannelId: Clone, SeriesId: Clone, VideoPostId: Clone, OwnedNFT: Clone>
-    VideoRecord<ChannelId, SeriesId, VideoPostId, OwnedNFT>
+impl<ChannelId: Clone, VideoPostId: Clone, OwnedNft: Clone>
+    VideoRecord<ChannelId, VideoPostId, OwnedNft>
 {
     /// Ensure nft is not issued
     pub fn ensure_nft_is_not_issued<T: Trait>(&self) -> DispatchResult {
-        ensure!(self.nft_status.is_none(), Error::<T>::NFTAlreadyExists);
+        ensure!(self.nft_status.is_none(), Error::<T>::NftAlreadyExists);
         Ok(())
     }
 
     /// Ensure nft is issued
-    pub fn ensure_nft_is_issued<T: Trait>(&self) -> Result<OwnedNFT, Error<T>> {
+    pub fn ensure_nft_is_issued<T: Trait>(&self) -> Result<OwnedNft, Error<T>> {
         if let Some(owned_nft) = &self.nft_status {
             Ok(owned_nft.clone())
         } else {
-            Err(Error::<T>::NFTDoesNotExist)
+            Err(Error::<T>::NftDoesNotExist)
         }
     }
 
     /// Set video nft status
-    pub fn set_nft_status(mut self, nft: OwnedNFT) -> Self {
+    pub fn set_nft_status(mut self, nft: OwnedNft) -> Self {
         self.nft_status = Some(nft);
         self
     }
@@ -630,9 +495,8 @@ impl<T: balances::Trait, ModId: Get<ModuleId>> ModuleAccount<T> for ModuleAccoun
     type ModuleId = ModId;
 }
 
-/// Local module account handler.
+/// Type Aliases
 pub type ContentTreasury<T> = ModuleAccountHandler<T, <T as Trait>::ModuleId>;
-
 pub type Balances<T> = balances::Module<T>;
 pub type BalanceOf<T> = <Balances<T> as Currency<<T as frame_system::Trait>::AccountId>>::Balance;
 pub type CurrencyOf<T> = common::currency::BalanceOf<T>;

+ 0 - 1
runtime-modules/storage/src/benchmarking.rs

@@ -14,7 +14,6 @@ use crate::{Call, Module, StorageBucketById, Trait};
 benchmarks! {
     where_clause {
         where T: balances::Trait,
-              T: membership::Trait,
               T: Trait,
     }
     _{ }

+ 16 - 16
runtime/src/constants.rs

@@ -102,22 +102,22 @@ pub mod fees {
 }
 
 parameter_types! {
-    pub const VotingLockId: LockIdentifier = [0; 8];
-    pub const CandidacyLockId: LockIdentifier = [1; 8];
-    pub const CouncilorLockId: LockIdentifier = [2; 8];
-    pub const ProposalsLockId: LockIdentifier = [5; 8];
-    pub const StorageWorkingGroupLockId: LockIdentifier = [6; 8];
-    pub const ContentWorkingGroupLockId: LockIdentifier = [7; 8];
-    pub const ForumGroupLockId: LockIdentifier = [8; 8];
-    pub const MembershipWorkingGroupLockId: LockIdentifier = [9; 8];
-    pub const InvitedMemberLockId: LockIdentifier = [10; 8];
-    pub const StakingCandidateLockId: LockIdentifier = [11; 8];
-    pub const BountyLockId: LockIdentifier = [12; 8];
-    pub const OperationsWorkingGroupAlphaLockId: LockIdentifier = [13; 8];
-    pub const GatewayWorkingGroupLockId: LockIdentifier = [14; 8];
-    pub const OperationsWorkingGroupBetaLockId: LockIdentifier = [15; 8];
-    pub const OperationsWorkingGroupGammaLockId: LockIdentifier = [16; 8];
-    pub const DistributionWorkingGroupLockId: LockIdentifier = [17; 8];
+    pub const VotingLockId: LockIdentifier = *b"voting  ";
+    pub const CandidacyLockId: LockIdentifier = *b"candidac";
+    pub const CouncilorLockId: LockIdentifier = *b"councilo";
+    pub const ProposalsLockId: LockIdentifier = *b"proposal";
+    pub const StorageWorkingGroupLockId: LockIdentifier = *b"wg-storg";
+    pub const ContentWorkingGroupLockId: LockIdentifier = *b"wg-contt";
+    pub const ForumGroupLockId: LockIdentifier = *b"wg-forum";
+    pub const MembershipWorkingGroupLockId: LockIdentifier = *b"wg-membr";
+    pub const InvitedMemberLockId: LockIdentifier = *b"invitemb";
+    pub const StakingCandidateLockId: LockIdentifier = *b"stakcand";
+    pub const BountyLockId: LockIdentifier = *b"bounty  ";
+    pub const OperationsWorkingGroupAlphaLockId: LockIdentifier = *b"wg-opera";
+    pub const GatewayWorkingGroupLockId: LockIdentifier = *b"wg-gatew";
+    pub const OperationsWorkingGroupBetaLockId: LockIdentifier = *b"wg-operb";
+    pub const OperationsWorkingGroupGammaLockId: LockIdentifier = *b"wg-operg";
+    pub const DistributionWorkingGroupLockId: LockIdentifier = *b"wg-distr";
 }
 
 // Staking lock ID used by nomination and validation in the staking pallet.

+ 0 - 6
runtime/src/lib.rs

@@ -444,7 +444,6 @@ impl common::currency::GovernanceCurrency for Runtime {
 
 parameter_types! {
     pub const MaxNumberOfCuratorsPerGroup: MaxNumber = 50;
-    pub const ChannelOwnershipPaymentEscrowId: [u8; 8] = *b"chescrow";
     pub const MaxModerators: u64 = 5;    // TODO: update
     pub const CleanupMargin: u32 = 3;    // TODO: update
     pub const CleanupCost: u32 = 1; // TODO: update
@@ -457,14 +456,9 @@ parameter_types! {
 
 impl content::Trait for Runtime {
     type Event = Event;
-    type ChannelOwnershipPaymentEscrowId = ChannelOwnershipPaymentEscrowId;
     type ChannelCategoryId = ChannelCategoryId;
     type VideoId = VideoId;
     type VideoCategoryId = VideoCategoryId;
-    type PlaylistId = PlaylistId;
-    type PersonId = PersonId;
-    type SeriesId = SeriesId;
-    type ChannelOwnershipTransferRequestId = ChannelOwnershipTransferRequestId;
     type MaxNumberOfCuratorsPerGroup = MaxNumberOfCuratorsPerGroup;
     type DataObjectStorage = Storage;
     type VideoPostId = VideoPostId;

+ 0 - 12
runtime/src/primitives.rs

@@ -55,18 +55,6 @@ pub type VideoId = u64;
 /// Content Directory Video Category identifier.
 pub type VideoCategoryId = u64;
 
-/// Content Directory Playlist identifier.
-pub type PlaylistId = u64;
-
-/// Content Directory Person identifier.
-pub type PersonId = u64;
-
-/// Content Directory Series identifier.
-pub type SeriesId = u64;
-
-/// Content Directory Channel transfer request identifier.
-pub type ChannelOwnershipTransferRequestId = u64;
-
 /// Curator group identifier.
 pub type CuratorGroupId = u64;
 

+ 1 - 1
runtime/src/runtime_api.rs

@@ -391,7 +391,7 @@ impl_runtime_apis! {
             add_benchmark!(params, batches, bounty, Bounty);
             add_benchmark!(params, batches, blog, Blog);
             add_benchmark!(params, batches, joystream_utility, JoystreamUtility);
-            add_benchmark!(params, batches, storage_v2, Storage);
+            add_benchmark!(params, batches, storage, Storage);
 
             if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
             Ok(batches)

+ 1 - 1
scripts/generate-weights.sh

@@ -68,4 +68,4 @@ benchmark membership
 benchmark bounty
 benchmark blog
 benchmark joystream_utility
-# benchmark storage_v2
+# benchmark storage

+ 19 - 71
types/augment/all/defs.json

@@ -675,20 +675,12 @@
         "assets_to_remove": "BTreeSet<DataObjectId>",
         "collaborators": "Option<BTreeSet<MemberId>>"
     },
-    "ChannelOwnershipTransferRequestId": "u64",
-    "ChannelOwnershipTransferRequest": {
-        "channel_id": "ChannelId",
-        "new_owner": "ChannelOwner",
-        "payment": "u128",
-        "new_reward_account": "Option<GenericAccountId>"
-    },
     "Video": {
         "in_channel": "ChannelId",
-        "in_series": "Option<SeriesId>",
         "is_censored": "bool",
         "enable_comments": "bool",
         "video_post_id": "Option<VideoPostId>",
-        "nft_status": "Option<OwnedNFT>"
+        "nft_status": "Option<OwnedNft>"
     },
     "VideoId": "u64",
     "VideoCategoryId": "u64",
@@ -702,7 +694,8 @@
     "VideoCreationParameters": {
         "assets": "Option<StorageAssets>",
         "meta": "Option<Bytes>",
-        "enable_comments": "bool"
+        "enable_comments": "bool",
+        "auto_issue_nft": "Option<NftIssuanceParameters>"
     },
     "VideoUpdateParameters": {
         "assets_to_upload": "Option<StorageAssets>",
@@ -710,64 +703,6 @@
         "assets_to_remove": "BTreeSet<DataObjectId>",
         "enable_comments": "Option<bool>"
     },
-    "Person": {
-        "controlled_by": "PersonController"
-    },
-    "PersonId": "u64",
-    "PersonController": {
-        "_enum": {
-            "Member": "MemberId",
-            "Curators": "Null"
-        }
-    },
-    "PersonActor": {
-        "_enum": {
-            "Member": "MemberId",
-            "Curator": "CuratorId"
-        }
-    },
-    "PersonCreationParameters": {
-        "assets": "StorageAssets",
-        "meta": "Bytes"
-    },
-    "PersonUpdateParameters": {
-        "assets": "Option<StorageAssets>",
-        "meta": "Option<Bytes>"
-    },
-    "Playlist": {
-        "in_channel": "ChannelId"
-    },
-    "PlaylistId": "u64",
-    "PlaylistCreationParameters": {
-        "meta": "Bytes"
-    },
-    "PlaylistUpdateParameters": {
-        "new_meta": "Bytes"
-    },
-    "SeriesId": "u64",
-    "Series": {
-        "in_channel": "ChannelId",
-        "seasons": "Vec<Season>"
-    },
-    "Season": {
-        "episodes": "Vec<VideoId>"
-    },
-    "SeriesParameters": {
-        "assets": "Option<StorageAssets>",
-        "seasons": "Option<Vec<Option<SeasonParameters>>>",
-        "meta": "Option<Bytes>"
-    },
-    "SeasonParameters": {
-        "assets": "Option<StorageAssets>",
-        "episodes": "Option<Vec<Option<EpisodeParemters>>>",
-        "meta": "Option<Bytes>"
-    },
-    "EpisodeParemters": {
-        "_enum": {
-            "NewVideo": "VideoCreationParameters",
-            "ExistingVideo": "VideoId"
-        }
-    },
     "MaxNumber": "u32",
     "IsCensored": "bool",
     "VideoMigrationConfig": {
@@ -855,14 +790,14 @@
             "BuyNow": "u128"
         }
     },
-    "NFTOwner": {
+    "NftOwner": {
         "_enum": {
             "ChannelOwner": "Null",
             "Member": "MemberId"
         }
     },
-    "OwnedNFT": {
-        "owner": "NFTOwner",
+    "OwnedNft": {
+        "owner": "NftOwner",
         "transactional_status": "TransactionalStatus",
         "creator_royalty": "Option<Royalty>"
     },
@@ -876,5 +811,18 @@
     },
     "CurrencyOf": "u128",
     "CurrencyAmount": "u128",
+    "InitTransactionalStatus": {
+        "_enum": {
+            "Idle": "Null",
+            "InitiatedOfferToMember": "(MemberId,Option<u128>)",
+            "Auction": "AuctionParams"
+        }
+    },
+    "NftIssuanceParameters": {
+        "royalty": "Option<Royalty>",
+        "nft_metadata": "Bytes",
+        "non_channel_owner": "Option<MemberId>",
+        "init_transactional_status": "InitTransactionalStatus"
+    },
     "AccountInfo": "AccountInfoWithRefCount"
 }

+ 24 - 107
types/augment/all/types.ts

@@ -254,17 +254,6 @@ export interface ChannelOwner extends Enum {
   readonly asCurators: CuratorGroupId;
 }
 
-/** @name ChannelOwnershipTransferRequest */
-export interface ChannelOwnershipTransferRequest extends Struct {
-  readonly channel_id: ChannelId;
-  readonly new_owner: ChannelOwner;
-  readonly payment: u128;
-  readonly new_reward_account: Option<GenericAccountId>;
-}
-
-/** @name ChannelOwnershipTransferRequestId */
-export interface ChannelOwnershipTransferRequestId extends u64 {}
-
 /** @name ChannelUpdateParameters */
 export interface ChannelUpdateParameters extends Struct {
   readonly assets_to_upload: Option<StorageAssets>;
@@ -478,14 +467,6 @@ export interface Entry extends Struct {
 /** @name EntryId */
 export interface EntryId extends u32 {}
 
-/** @name EpisodeParemters */
-export interface EpisodeParemters extends Enum {
-  readonly isNewVideo: boolean;
-  readonly asNewVideo: VideoCreationParameters;
-  readonly isExistingVideo: boolean;
-  readonly asExistingVideo: VideoId;
-}
-
 /** @name ExecutionFailed */
 export interface ExecutionFailed extends Struct {
   readonly error: Text;
@@ -550,6 +531,15 @@ export interface GeneralProposalParameters extends Struct {
   readonly exact_execution_block: Option<u32>;
 }
 
+/** @name InitTransactionalStatus */
+export interface InitTransactionalStatus extends Enum {
+  readonly isIdle: boolean;
+  readonly isInitiatedOfferToMember: boolean;
+  readonly asInitiatedOfferToMember: ITuple<[MemberId, Option<u128>]>;
+  readonly isAuction: boolean;
+  readonly asAuction: AuctionParams;
+}
+
 /** @name InputValidationLengthConstraint */
 export interface InputValidationLengthConstraint extends Struct {
   readonly min: u16;
@@ -598,8 +588,16 @@ export interface ModeratorId extends u64 {}
 /** @name ModeratorSet */
 export interface ModeratorSet extends BTreeSet<MemberId> {}
 
-/** @name NFTOwner */
-export interface NFTOwner extends Enum {
+/** @name NftIssuanceParameters */
+export interface NftIssuanceParameters extends Struct {
+  readonly royalty: Option<Royalty>;
+  readonly nft_metadata: Bytes;
+  readonly non_channel_owner: Option<MemberId>;
+  readonly init_transactional_status: InitTransactionalStatus;
+}
+
+/** @name NftOwner */
+export interface NftOwner extends Enum {
   readonly isChannelOwner: boolean;
   readonly isMember: boolean;
   readonly asMember: MemberId;
@@ -650,9 +648,9 @@ export interface OracleWorkEntryJudgment_Winner extends Struct {
   readonly reward: u128;
 }
 
-/** @name OwnedNFT */
-export interface OwnedNFT extends Struct {
-  readonly owner: NFTOwner;
+/** @name OwnedNft */
+export interface OwnedNft extends Struct {
+  readonly owner: NftOwner;
   readonly transactional_status: TransactionalStatus;
   readonly creator_royalty: Option<Royalty>;
 }
@@ -666,59 +664,6 @@ export interface Penalty extends Struct {
   readonly slashing_amount: u128;
 }
 
-/** @name Person */
-export interface Person extends Struct {
-  readonly controlled_by: PersonController;
-}
-
-/** @name PersonActor */
-export interface PersonActor extends Enum {
-  readonly isMember: boolean;
-  readonly asMember: MemberId;
-  readonly isCurator: boolean;
-  readonly asCurator: CuratorId;
-}
-
-/** @name PersonController */
-export interface PersonController extends Enum {
-  readonly isMember: boolean;
-  readonly asMember: MemberId;
-  readonly isCurators: boolean;
-}
-
-/** @name PersonCreationParameters */
-export interface PersonCreationParameters extends Struct {
-  readonly assets: StorageAssets;
-  readonly meta: Bytes;
-}
-
-/** @name PersonId */
-export interface PersonId extends u64 {}
-
-/** @name PersonUpdateParameters */
-export interface PersonUpdateParameters extends Struct {
-  readonly assets: Option<StorageAssets>;
-  readonly meta: Option<Bytes>;
-}
-
-/** @name Playlist */
-export interface Playlist extends Struct {
-  readonly in_channel: ChannelId;
-}
-
-/** @name PlaylistCreationParameters */
-export interface PlaylistCreationParameters extends Struct {
-  readonly meta: Bytes;
-}
-
-/** @name PlaylistId */
-export interface PlaylistId extends u64 {}
-
-/** @name PlaylistUpdateParameters */
-export interface PlaylistUpdateParameters extends Struct {
-  readonly new_meta: Bytes;
-}
-
 /** @name Poll */
 export interface Poll extends Struct {
   readonly description_hash: Hash;
@@ -981,34 +926,6 @@ export interface RewardPaymentType extends Enum {
 /** @name Royalty */
 export interface Royalty extends u64 {}
 
-/** @name Season */
-export interface Season extends Struct {
-  readonly episodes: Vec<VideoId>;
-}
-
-/** @name SeasonParameters */
-export interface SeasonParameters extends Struct {
-  readonly assets: Option<StorageAssets>;
-  readonly episodes: Option<Vec<Option<EpisodeParemters>>>;
-  readonly meta: Option<Bytes>;
-}
-
-/** @name Series */
-export interface Series extends Struct {
-  readonly in_channel: ChannelId;
-  readonly seasons: Vec<Season>;
-}
-
-/** @name SeriesId */
-export interface SeriesId extends u64 {}
-
-/** @name SeriesParameters */
-export interface SeriesParameters extends Struct {
-  readonly assets: Option<StorageAssets>;
-  readonly seasons: Option<Vec<Option<SeasonParameters>>>;
-  readonly meta: Option<Bytes>;
-}
-
 /** @name SetLeadParams */
 export interface SetLeadParams extends ITuple<[MemberId, AccountId]> {}
 
@@ -1157,11 +1074,10 @@ export interface Url extends Text {}
 /** @name Video */
 export interface Video extends Struct {
   readonly in_channel: ChannelId;
-  readonly in_series: Option<SeriesId>;
   readonly is_censored: bool;
   readonly enable_comments: bool;
   readonly video_post_id: Option<VideoPostId>;
-  readonly nft_status: Option<OwnedNFT>;
+  readonly nft_status: Option<OwnedNft>;
 }
 
 /** @name VideoCategory */
@@ -1185,6 +1101,7 @@ export interface VideoCreationParameters extends Struct {
   readonly assets: Option<StorageAssets>;
   readonly meta: Option<Bytes>;
   readonly enable_comments: bool;
+  readonly auto_issue_nft: Option<NftIssuanceParameters>;
 }
 
 /** @name VideoId */

+ 24 - 93
types/src/content/index.ts

@@ -10,10 +10,6 @@ export class CuratorGroupId extends u64 {}
 export class ChannelCategoryId extends u64 {}
 export class VideoId extends u64 {}
 export class VideoCategoryId extends u64 {}
-export class PlaylistId extends u64 {}
-export class PersonId extends u64 {}
-export class SeriesId extends u64 {}
-export class ChannelOwnershipTransferRequestId extends u64 {}
 export class MaxNumber extends u32 {}
 export class IsCensored extends bool {}
 export class VideoPostId extends u64 {}
@@ -64,13 +60,13 @@ export class TransactionalStatus extends JoyEnum({
   BuyNow: Balance,
 }) {}
 
-export class NFTOwner extends JoyEnum({
+export class NftOwner extends JoyEnum({
   ChannelOwner: Null,
   Member: MemberId,
 }) {}
 
-export class OwnedNFT extends JoyStructDecorated({
-  owner: NFTOwner,
+export class OwnedNft extends JoyStructDecorated({
+  owner: NftOwner,
   transactional_status: TransactionalStatus,
   creator_royalty: Option.with(Royalty),
 }) {}
@@ -84,7 +80,20 @@ export class AuctionParams extends JoyStructDecorated({
   whitelist: BTreeSet.with(MemberId),
 }) {}
 
-// end of NFT types
+export class InitTransactionalStatus extends JoyEnum({
+  Idle: Null,
+  InitiatedOfferToMember: Tuple.with([MemberId, Option.with(Balance)]),
+  Auction: AuctionParams,
+}) {}
+
+export class NftIssuanceParameters extends JoyStructDecorated({
+  royalty: Option.with(Royalty),
+  nft_metadata: Bytes,
+  non_channel_owner: Option.with(MemberId),
+  init_transactional_status: InitTransactionalStatus,
+}) {}
+
+// end of Nft types
 
 export class StorageAssets extends JoyStructDecorated({
   object_creation_list: Vec.with(DataObjectCreationParameters),
@@ -166,17 +175,17 @@ export class VideoCategoryUpdateParameters extends JoyStructDecorated({
 
 export class Video extends JoyStructDecorated({
   in_channel: ChannelId,
-  in_series: Option.with(SeriesId),
   is_censored: bool,
   enable_comments: bool,
   video_post_id: Option.with(VideoPostId),
-  nft_status: Option.with(OwnedNFT),
+  nft_status: Option.with(OwnedNft),
 }) {}
 
 export class VideoCreationParameters extends JoyStructDecorated({
   assets: Option.with(StorageAssets),
   meta: Option.with(Bytes),
   enable_comments: bool,
+  auto_issue_nft: Option.with(NftIssuanceParameters),
 }) {}
 
 export class VideoUpdateParameters extends JoyStructDecorated({
@@ -186,68 +195,6 @@ export class VideoUpdateParameters extends JoyStructDecorated({
   enable_comments: Option.with(bool),
 }) {}
 
-export class Playlist extends JoyStructDecorated({
-  in_channel: ChannelId,
-}) {}
-
-export class PlaylistCreationParameters extends JoyStructDecorated({
-  meta: Bytes,
-}) {}
-
-export class PlaylistUpdateParameters extends JoyStructDecorated({
-  new_meta: Bytes,
-}) {}
-
-export class EpisodeParemters extends JoyEnum({
-  NewVideo: VideoCreationParameters,
-  ExistingVideo: VideoId,
-}) {}
-
-export class Season extends JoyStructDecorated({
-  episodes: Vec.with(VideoId),
-}) {}
-
-export class SeasonParameters extends JoyStructDecorated({
-  assets: Option.with(StorageAssets),
-  episodes: Option.with(Vec.with(Option.with(EpisodeParemters))),
-  meta: Option.with(Bytes),
-}) {}
-
-export class Series extends JoyStructDecorated({
-  in_channel: ChannelId,
-  seasons: Vec.with(Season),
-}) {}
-
-export class SeriesParameters extends JoyStructDecorated({
-  assets: Option.with(StorageAssets),
-  seasons: Option.with(Vec.with(Option.with(SeasonParameters))),
-  meta: Option.with(Bytes),
-}) {}
-
-export class PersonController extends JoyEnum({
-  Member: MemberId,
-  Curators: Null,
-}) {}
-
-export class Person extends JoyStructDecorated({
-  controlled_by: PersonController,
-}) {}
-
-export class PersonCreationParameters extends JoyStructDecorated({
-  assets: StorageAssets,
-  meta: Bytes,
-}) {}
-
-export class PersonUpdateParameters extends JoyStructDecorated({
-  assets: Option.with(StorageAssets),
-  meta: Option.with(Bytes),
-}) {}
-
-export class PersonActor extends JoyEnum({
-  Member: MemberId,
-  Curator: CuratorId,
-}) {}
-
 export class VideoMigrationConfig extends JoyStructDecorated({
   current_id: VideoId,
   final_id: VideoId,
@@ -312,8 +259,6 @@ export const contentTypes = {
   ChannelCategoryUpdateParameters,
   ChannelCreationParameters,
   ChannelUpdateParameters,
-  ChannelOwnershipTransferRequestId,
-  ChannelOwnershipTransferRequest,
   Video,
   VideoId,
   VideoCategoryId,
@@ -322,22 +267,6 @@ export const contentTypes = {
   VideoCategoryUpdateParameters,
   VideoCreationParameters,
   VideoUpdateParameters,
-  Person,
-  PersonId,
-  PersonController,
-  PersonActor,
-  PersonCreationParameters,
-  PersonUpdateParameters,
-  Playlist,
-  PlaylistId,
-  PlaylistCreationParameters,
-  PlaylistUpdateParameters,
-  SeriesId,
-  Series,
-  Season,
-  SeriesParameters,
-  SeasonParameters,
-  EpisodeParemters,
   MaxNumber,
   IsCensored,
   VideoMigrationConfig,
@@ -353,7 +282,7 @@ export const contentTypes = {
   VideoPostDeletionParameters,
   PullPayment,
   ModeratorSet,
-  // NFT
+  // Nft
   Royalty,
   IsExtended,
   EnglishAuctionDetails,
@@ -362,11 +291,13 @@ export const contentTypes = {
   Bid,
   Auction,
   TransactionalStatus,
-  NFTOwner,
-  OwnedNFT,
+  NftOwner,
+  OwnedNft,
   AuctionParams,
   CurrencyOf,
   CurrencyAmount,
+  InitTransactionalStatus,
+  NftIssuanceParameters,
 }
 
 export default contentTypes