Browse Source

vnft_auction: enable vnft offers

iorveth 3 years ago
parent
commit
2d1c627534

+ 12 - 9
runtime-modules/content/src/lib.rs

@@ -1219,7 +1219,7 @@ decl_module! {
             Self::issue_vnft(&mut video, video_id, to, royalty, metadata);
         }
 
-        /// Offer vNFT 
+        /// Offer vNFT
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn offer_vnft(
             origin,
@@ -1246,8 +1246,14 @@ decl_module! {
             // == MUTATION SAFE ==
             //
 
-            // Set nft transactional status to InitiatedTransferToMember
-            video.set_pending_transfer_transactional_status(to, price);
+            // Set nft transactional status to InitiatedOfferToMember
+            let offer_details = if let Some(price) = price {
+                Some(OfferDetails::new(from_account_id, price))
+            } else {
+                None
+            };
+
+            video.set_pending_offer_transactional_status(to, offer_details);
 
             // Trigger event
             Self::deposit_event(RawEvent::TransferStarted(video_id, from, to));
@@ -1269,7 +1275,7 @@ decl_module! {
             let video = Self::ensure_video_exists(&video_id)?;
 
             // Ensure given pending transfer exists
-            video.ensure_pending_transfer_exists::<T>()?;
+            video.ensure_pending_offer_exists::<T>()?;
 
             // Ensure provided participant owns vnft
             video.ensure_vnft_ownership::<T>(&ChannelOwner::Member(participant_id))?;
@@ -1302,18 +1308,15 @@ decl_module! {
             // Ensure given video exists
             let video = Self::ensure_video_exists(&video_id)?;
 
-            // Ensure nft transactional status is set to InitiatedTransferToMember
-            video.ensure_pending_transfer_exists::<T>()?;
-
             // Ensure new pending transfer available to proceed
-            video.ensure_new_pending_transfer_available::<T>(participant_id)?;
+            Self::ensure_new_pending_offer_available_to_proceed(&video, participant_id, &participant_account_id)?;
 
             //
             // == MUTATION SAFE ==
             //
 
             // Complete vnft transfer
-            let video = video.complete_vnft_transfer(ChannelOwner::Member(participant_id));
+            let video = Self::complete_vnft_offer(video, participant_account_id);
 
             VideoById::<T>::insert(video_id, video);
 

+ 44 - 0
runtime-modules/content/src/nft/mod.rs

@@ -180,6 +180,50 @@ impl<T: Trait> Module<T> {
         ));
     }
 
+    /// Ensure new pending offer for given participant is available to proceed
+    pub fn ensure_new_pending_offer_available_to_proceed(
+        video: &Video<T>,
+        participant: T::MemberId,
+        participant_account_id: &T::AccountId,
+    ) -> DispatchResult {
+        match &video.nft_status {
+            NFTStatus::Owned(OwnedNFT {
+                transactional_status: TransactionalStatus::InitiatedOfferToMember(to, offer_details),
+                ..
+            }) if participant == *to => {
+                if let Some(offer_details) = offer_details {
+                    ensure!(
+                        T::Currency::can_slash(participant_account_id, offer_details.price),
+                        Error::<T>::InsufficientBalance
+                    );
+                }
+            }
+            _ => return Err(Error::<T>::NoIncomingTransfers.into()),
+        }
+        Ok(())
+    }
+
+    /// Completes vnft offer
+    pub fn complete_vnft_offer(mut video: Video<T>, new_owner_account_id: T::AccountId) -> Video<T> {
+        if let NFTStatus::Owned(OwnedNFT {
+            transactional_status: TransactionalStatus::InitiatedOfferToMember(to, offer_details),
+            ref mut owner,
+            ..
+        }) = &mut video.nft_status
+        {
+            if let Some(offer_details) = offer_details {
+
+                T::Currency::slash(&new_owner_account_id, offer_details.price);
+
+                T::Currency::deposit_creating(&offer_details.account_id, offer_details.price);
+            }
+          
+            *owner = NFTOwner::Member(*to);
+        }
+
+        video.set_idle_transactional_status()
+    }
+
     /// Complete vnft transfer
     pub(crate) fn complete_vnft_auction_transfer(
         video: &mut Video<T>,

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

@@ -10,17 +10,35 @@ pub type MemberId<T> = <T as membership::Trait>::MemberId;
 /// Owner royalty
 pub type Royalty = Perbill;
 
+/// Offer details
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
+pub struct OfferDetails<AccountId: Default, Balance: Default> {
+    pub account_id: AccountId,
+    pub price: Balance,
+}
+
+impl<AccountId: Default, Balance: Default> OfferDetails<AccountId, Balance> {
+    /// Creates new `OfferDetails` instance
+    pub fn new(account_id: AccountId, price: Balance) -> Self {
+        Self {
+            account_id,
+            price,
+        }
+    }
+}
+
 /// NFT transactional status
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
 pub enum TransactionalStatus<
-    AccountId,
+    AccountId: Default,
     BlockNumber: BaseArithmetic + Copy,
     MemberId: Default + Copy + Ord,
-    Balance,
+    Balance: Default,
 > {
     Idle,
-    InitiatedTransferToMember(MemberId, Option<Balance>),
+    InitiatedOfferToMember(MemberId, Option<OfferDetails<AccountId, Balance>>),
     Auction(AuctionRecord<AccountId, BlockNumber, Balance, MemberId>),
 }
 
@@ -55,12 +73,12 @@ impl<MemberId: Default + Copy, CuratorGroupId: Default + Copy, DAOId: Default +
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
 pub struct OwnedNFT<
-    AccountId,
+    AccountId: Default,
     BlockNumber: BaseArithmetic + Copy,
     MemberId: Default + Copy + Ord,
     CuratorGroupId: Default + Copy,
     DAOId: Default + Copy,
-    Balance,
+    Balance: Default,
 > {
     pub owner: NFTOwner<MemberId, CuratorGroupId, DAOId>,
     pub transactional_status: TransactionalStatus<AccountId, BlockNumber, MemberId, Balance>,
@@ -70,12 +88,12 @@ pub struct OwnedNFT<
 }
 
 impl<
-        AccountId,
+        AccountId: Default,
         BlockNumber: BaseArithmetic + Copy,
         MemberId: Default + Copy + PartialEq + Ord,
         CuratorGroupId: Default + Copy + PartialEq,
         DAOId: Default + Copy + PartialEq,
-        Balance,
+        Balance: Default,
     > OwnedNFT<AccountId, BlockNumber, MemberId, CuratorGroupId, DAOId, Balance>
 {
     /// Whether content actor is nft owner
@@ -110,24 +128,24 @@ impl<
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
 pub enum NFTStatus<
-    AccountId,
+    AccountId: Default,
     BlockNumber: BaseArithmetic + Copy,
     MemberId: Default + Copy + Ord,
     CuratorGroupId: Default + Copy,
     DAOId: Default + Copy,
-    Balance,
+    Balance: Default,
 > {
     NoneIssued,
     Owned(OwnedNFT<AccountId, BlockNumber, MemberId, CuratorGroupId, DAOId, Balance>),
 }
 
 impl<
-        AccountId,
+        AccountId: Default,
         BlockNumber: BaseArithmetic + Copy,
         MemberId: Default + Copy + Ord,
         CuratorGroupId: Default + Copy,
         DAOId: Default + Copy,
-        Balance,
+        Balance: Default,
     > Default for NFTStatus<AccountId, BlockNumber, MemberId, CuratorGroupId, DAOId, Balance>
 {
     fn default() -> Self {

+ 15 - 44
runtime-modules/content/src/types.rs

@@ -214,12 +214,12 @@ pub struct VideoUpdateParameters<ContentParameters> {
 pub struct VideoRecord<
     ChannelId,
     SeriesId,
-    AccountId,
+    AccountId: Default,
     BlockNumber: BaseArithmetic + Copy,
     MemberId: Default + Copy + Ord,
     CuratorGroupId: Default + Copy,
     DAOId: Default + Copy,
-    Balance,
+    Balance: Default,
 > {
     pub in_channel: ChannelId,
     // keep track of which season the video is in if it is an 'episode'
@@ -239,7 +239,7 @@ impl<
         MemberId: Default + Copy + PartialEq + Ord,
         CuratorGroupId: Default + Copy + PartialEq,
         DAOId: Default + Copy + PartialEq,
-        Balance: Clone,
+        Balance: Clone + Default,
     >
     VideoRecord<
         ChannelId,
@@ -414,22 +414,6 @@ impl<
         self
     }
 
-    /// Completes vnft transfer
-    pub fn complete_vnft_transfer(
-        mut self,
-        new_owner: ChannelOwner<MemberId, CuratorGroupId, DAOId>,
-    ) -> Self {
-        if let NFTStatus::Owned(OwnedNFT {
-            transactional_status: TransactionalStatus::InitiatedTransferToMember(..),
-            ref mut owner,
-            ..
-        }) = self.nft_status
-        {
-            *owner = NFTOwner::ChannelOwner(new_owner);
-        }
-        self.set_idle_transactional_status()
-    }
-
     /// Set nft transactional status to `Idle`
     pub fn set_idle_transactional_status(mut self) -> Self {
         if let NFTStatus::Owned(owned_nft) = &mut self.nft_status {
@@ -438,50 +422,37 @@ impl<
         self
     }
 
-    /// Set nft transactional status to `InitiatedTransferToMember`
-    pub fn set_pending_transfer_transactional_status(mut self, to: MemberId, price: Balance) -> Self {
+    /// Set nft transactional status to `InitiatedOfferToMember`
+    pub fn set_pending_offer_transactional_status(
+        mut self,
+        to: MemberId,
+        offer_details: Option<OfferDetails<AccountId, Balance>>,
+    ) -> Self {
         if let NFTStatus::Owned(owned_nft) = &mut self.nft_status {
-            owned_nft.transactional_status = TransactionalStatus::InitiatedTransferToMember(to, price);
+            owned_nft.transactional_status = TransactionalStatus::InitiatedOfferToMember(to, offer_details);
         }
         self
     }
 
     /// Whether pending tansfer exist
-    pub fn is_pending_transfer_transactional_status(&self) -> bool {
+    pub fn is_pending_offer_transactional_status(&self) -> bool {
         matches!(
             self.nft_status,
             NFTStatus::Owned(OwnedNFT {
-                transactional_status: TransactionalStatus::InitiatedTransferToMember(..),
+                transactional_status: TransactionalStatus::InitiatedOfferToMember(..),
                 ..
             })
         )
     }
 
-    /// Ensure vNFT has pending transfer
-    pub fn ensure_pending_transfer_exists<T: Trait>(&self) -> DispatchResult {
+    /// Ensure vNFT has pending offer
+    pub fn ensure_pending_offer_exists<T: Trait>(&self) -> DispatchResult {
         ensure!(
-            self.is_pending_transfer_transactional_status(),
+            self.is_pending_offer_transactional_status(),
             Error::<T>::PendingTransferDoesNotExist
         );
         Ok(())
     }
-
-    /// Ensure new pending transfer for given participant available to proceed
-    pub fn ensure_new_pending_transfer_available<T: Trait>(
-        &self,
-        participant: MemberId,
-    ) -> DispatchResult {
-        let is_available = matches!(
-            self.nft_status,
-            NFTStatus::Owned(OwnedNFT {
-                transactional_status: TransactionalStatus::InitiatedTransferToMember(to, _),
-                ..
-            }) if participant == to
-        );
-
-        ensure!(is_available, Error::<T>::NoIncomingTransfers);
-        Ok(())
-    }
 }
 
 /// Video alias type for simplification.