git.delta.rocks / unique-network / refs/commits / bf6a3d46a94a

difftreelog

Add chain extension for transfer

Greg Zaitsev2021-01-28parent: #0c7b324.patch.diff
in: master

4 files changed

modifiedCargo.lockdiffbeforeafterboth
before · Cargo.lock
702 packageslockfile v1
after · Cargo.lock
704 packageslockfile v1
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -1047,32 +1047,8 @@
         ///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)
         #[weight = <T as Config>::WeightInfo::transfer()]
         pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {
-
             let sender = ensure_signed(origin)?;
-            let target_collection = <Collection<T>>::get(collection_id);
-
-            // Limits check
-            Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;
-
-            // Transfer permissions check
-            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||
-                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
-                Error::<T>::NoPermission);
-
-            if target_collection.access == AccessMode::WhiteList {
-                Self::check_white_list(collection_id, &sender)?;
-                Self::check_white_list(collection_id, &recipient)?;
-            }
-
-            match target_collection.mode
-            {
-                CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,
-                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,
-                CollectionMode::ReFungible(_)  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,
-                _ => ()
-            };
-
-            Ok(())
+            Self::transfer_internal(sender, recipient, collection_id, item_id, value)
         }
 
         /// Set, change, or remove approved address to transfer the ownership of the NFT.
@@ -1554,6 +1530,35 @@
 
 impl<T: Config> Module<T> {
 
+    pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {
+
+        let target_collection = <Collection<T>>::get(collection_id);
+
+        // Limits check
+        Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;
+
+        // Transfer permissions check
+        ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||
+            Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
+            Error::<T>::NoPermission);
+
+        if target_collection.access == AccessMode::WhiteList {
+            Self::check_white_list(collection_id, &sender)?;
+            Self::check_white_list(collection_id, &recipient)?;
+        }
+
+        match target_collection.mode
+        {
+            CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,
+            CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,
+            CollectionMode::ReFungible(_)  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,
+            _ => ()
+        };
+
+        Ok(())
+    }
+
+
     fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {
 
         // check token limit and account token limit
addedruntime/src/chain_extension.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/src/chain_extension.rs
@@ -0,0 +1,98 @@
+//! NFT Chain Extension
+
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
+use codec::{Decode, Encode};
+
+pub use pallet_contracts::chain_extension::RetVal;
+use pallet_contracts::chain_extension::{
+    ChainExtension, Environment, Ext, InitState, SysConfig, UncheckedFrom,
+};
+
+pub use frame_support::debug;
+use frame_support::dispatch::DispatchError;
+
+extern crate pallet_nft;
+pub use pallet_nft::*;
+use crate::Runtime;
+use sp_runtime::AccountId32;
+use crate::Vec;
+use frame_system::Origin;
+
+/// Transfer parameters
+#[derive(Debug, PartialEq, Encode, Decode)]
+pub struct NFTExtTransfer<E: Ext> {
+    pub recipient: <E::T as SysConfig>::AccountId,
+    pub collection_id: u32,
+    pub token_id: u32,
+    pub amount: u128,
+}
+
+/// The chain Extension of NFT pallet
+pub struct NFTExtension;
+
+// pub trait ToAccount32 {
+//     fn to_account32<E: Ext>(addr: <E::T as SysConfig>::AccountId);
+// }
+
+// impl ToAccount32 for NFTExtension {
+//     fn to_account32<E: Ext>(addr: <E::T as SysConfig>::AccountId) 
+//     where
+//         <E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
+//     {
+//         let mut bytes: [u8; 32];
+//         let addrVec: Vec<u8> = addr.encode();
+//         for i in 0..32 {
+//             bytes[i] = addrVec[i];
+//         }
+//         AccountId32::from(bytes)
+//     }
+
+// }
+
+impl ChainExtension for NFTExtension {
+    fn call<E: Ext>(func_id: u32, env: Environment<E, InitState>) -> Result<RetVal, DispatchError>
+    where
+        <E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
+    {
+        // The memory of the vm stores buf in scale-codec
+        match func_id {
+            0 => {
+                let mut env = env.buf_in_buf_out();
+                let input: NFTExtTransfer<E> = env.read_as()?;
+
+                // Sender to AccountId32
+                let mut bytesSender: [u8; 32] = [0; 32];
+                let addrVecSender: Vec<u8> = env.ext().caller().encode();
+                for i in 0..32 {
+                    bytesSender[i] = addrVecSender[i];
+                }
+                let sender = AccountId32::from(bytesSender);
+
+                // Recipient to AccountId32
+                let mut bytesRec: [u8; 32] = [0; 32];
+                let addrVecRec: Vec<u8> = input.recipient.encode();
+                for i in 0..32 {
+                    bytesRec[i] = addrVecRec[i];
+                }
+                let recipient = AccountId32::from(bytesRec);
+
+
+
+                match pallet_nft::Module::<Runtime>::transfer_internal(sender, recipient, input.collection_id, input.token_id, input.amount) {
+                    Ok(_) => Ok(RetVal::Converging(func_id)),
+                    DispatchError => Err(DispatchError::Other("Transfer error"))
+                }
+
+                
+            },
+			_ => {
+				panic!("Passed unknown func_id to test chain extension: {}", func_id);
+            }
+        }
+    }
+}
+
modifiedruntime/src/lib.rsdiffbeforeafterboth
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -63,6 +63,9 @@
 
 pub use pallet_timestamp::Call as TimestampCall;
 
+mod chain_extension;
+use crate::chain_extension::NFTExtension;
+
 /// Struct that handles the conversion of Balance -> `u64`. This is used for
 /// staking's election calculation.
 pub struct CurrencyToVoteHandler;
@@ -413,7 +416,7 @@
 	type MaxValueSize = MaxValueSize;
 	type WeightPrice = pallet_transaction_payment::Module<Self>;
 	type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;
-	type ChainExtension = ();
+	type ChainExtension = NFTExtension;
 	type DeletionQueueDepth = DeletionQueueDepth;
 	type DeletionWeightLimit = DeletionWeightLimit;
 }