git.delta.rocks / unique-network / refs/commits / 675d1d0e13af

difftreelog

Offchain schema added

str-mv2020-08-03parent: #a3fcd2f.patch.diff
in: master

6 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3086,6 +3086,7 @@
  "frame-support",
  "frame-system",
  "parity-scale-codec",
+ "serde",
  "sp-core",
  "sp-io",
  "sp-runtime",
modifiedpallets/nft/Cargo.tomldiffbeforeafterboth
--- a/pallets/nft/Cargo.toml
+++ b/pallets/nft/Cargo.toml
@@ -32,6 +32,10 @@
 git = 'https://github.com/usetech-llc/substrate.git'
 branch = 'rc4_ext_dispatch_reenabled'
 version = '2.0.0-rc4'
+	
+[dependencies]
+# third-party dependencies
+serde = { version = "1.0.102", features = ["derive"] }
 
 [package]
 authors = ['Substrate DevHub <https://github.com/substrate-developer-hub>']
@@ -49,6 +53,7 @@
 default = ['std']
 std = [
     'codec/std',
+    "serde/std",
     'frame-support/std',
     'frame-system/std',
     'sp-runtime/std',
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -14,6 +14,27 @@
 #[cfg(test)]
 mod tests;
 
+#[derive(Encode, Decode, Debug, Eq, Clone, PartialEq)]
+pub enum CollectionMode {
+    Invalid,
+    // custom data size
+    NFT(u32),
+    // amount
+	Fungible(u32),
+	ReFungible,
+}
+
+impl Into<u8> for CollectionMode {
+    fn into(self) -> u8{
+        match self {
+            CollectionMode::Invalid => 0,
+            CollectionMode::NFT(_) => 1,
+            CollectionMode::Fungible(_) => 2,
+            CollectionMode::ReFungible => 3,
+        }
+    }
+}
+
 #[derive(Encode, Decode, Debug, Clone, PartialEq)]
 pub enum AccessMode {
     Normal,
@@ -21,13 +42,6 @@
 }
 impl Default for AccessMode { fn default() -> Self { Self::Normal } }
 
-#[derive(Encode, Decode, Debug, Eq, Clone, PartialEq)]
-pub enum CollectionMode {
-    Invalid,
-	NFT,
-	Fungible,
-	ReFungible,
-}
 impl Default for CollectionMode { fn default() -> Self { Self::Invalid } }
 
 #[derive(Encode, Decode, Default, Clone, PartialEq)]
@@ -49,6 +63,9 @@
     pub description: Vec<u16>, // 256 include null escape char
     pub token_prefix: Vec<u8>, // 16 include null escape char
     pub custom_data_size: u32,
+    pub offchain_schema: Vec<u8>,
+    pub sponsor: AccountId,    // Who pays fees. If set to default address, the fees are applied to the transaction sender
+    pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship
 }
 
 #[derive(Encode, Decode, Default, Clone, PartialEq)]
@@ -88,8 +105,10 @@
 decl_storage! {
     trait Store for Module<T: Trait> as Nft {
 
-        // Next available collection ID
-        NextCollectionID get(fn next_collection_id): u64;
+        // Private members
+        NextCollectionID: u64;
+        ItemListIndex: map hasher(blake2_128_concat) u64 => u64;
+
         pub Collection get(fn collection): map hasher(identity) u64 => CollectionType<T::AccountId>;
         pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;
 
@@ -101,7 +120,6 @@
         pub NftItemList get(fn nft_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;
         pub FungibleItemList get(fn fungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;
         pub ReFungibleItemList get(fn refungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;
-        ItemListIndex get(fn item_index): map hasher(blake2_128_concat) u64 => u64;
 
         pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;
     }
@@ -132,36 +150,19 @@
                                     collection_name: Vec<u16>,
                                     collection_description: Vec<u16>,
                                     token_prefix: Vec<u8>,
-                                    mode: u8,
-                                    decimal_points: u32,
-                                    custom_data_size: u32) -> DispatchResult {
+                                    mode: CollectionMode) -> DispatchResult {
 
             // Anyone can create a collection
             let who = ensure_signed(origin)?;
-            let collection_mode: CollectionMode;
-            match mode {
-                1 => collection_mode = CollectionMode::NFT,
-                2 => collection_mode = CollectionMode::Fungible,
-                3 => collection_mode = CollectionMode::ReFungible,
-                _ => collection_mode = CollectionMode::Invalid
-            }
-
-            // check type
-            ensure!((collection_mode == CollectionMode::Fungible || collection_mode == CollectionMode::NFT || collection_mode == CollectionMode::ReFungible), 
-                "Collection mode must be Fungible, NFT or ReFungible");          
-
-            // NFT checks
-            if collection_mode == CollectionMode::NFT
-            {
-                ensure!(decimal_points == 0, "Collection in NFT mode must have zero in decimal_points parameter"); 
-            }
+            let custom_data_size = match mode {
+                CollectionMode::NFT(size) => size,
+                _ => 0
+            };
 
-            // Fungible checks
-            if collection_mode == CollectionMode::Fungible
-            {
-                ensure!(custom_data_size == 0, "Collection in Fungible mode must have zero in custom_data_size parameter"); 
-                ensure!(decimal_points != 0, "Collection in Fungible mode must have not zero in decimal_points parameter"); 
-            }
+            let decimal_points = match mode {
+                CollectionMode::Fungible(points) => points,
+                _ => 0
+            };
 
             // check params
             ensure!(decimal_points < 100, "decimal_points parameter must be lower than 100"); 
@@ -189,20 +190,23 @@
             let new_collection = CollectionType {
                 owner: who.clone(),
                 name: name,
-                mode: collection_mode.clone(),
+                mode: mode.clone(),
                 access: AccessMode::Normal,
                 description: description,
                 decimal_points: decimal_points,
                 token_prefix: prefix,
                 next_item_id: next_id,
+                offchain_schema: Vec::new(),
                 custom_data_size: custom_data_size,
+                sponsor: T::AccountId::default(),
+                unconfirmed_sponsor: T::AccountId::default(),
             };
 
             // Add new collection to map
             <Collection<T>>::insert(next_id, new_collection);
 
             // call event
-            Self::deposit_event(RawEvent::Created(next_id, mode, who.clone()));
+            Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));
 
             Ok(())
         }
@@ -285,19 +289,21 @@
             <Balance<T>>::insert(collection_id, owner.clone(), new_balance);
 
             // TODO: implement other modes
-            ensure!(target_collection.mode == CollectionMode::NFT, "Collection type not implemented");
-
-            if target_collection.mode == CollectionMode::NFT
+            match target_collection.mode 
             {
+                CollectionMode::NFT(_) => {
                 // Create nft item
-                let item = NftItemType {
-                    collection: collection_id,
-                    owner: owner,
-                    data: properties,
-                };
-
-                Self::add_nft_item(item)?;
-            }
+                    let item = NftItemType {
+                        collection: collection_id,
+                        owner: owner,
+                        data: properties,
+                    };
+    
+                    Self::add_nft_item(item)?;
+    
+                },
+                _ => ()
+            };
 
             // call event
             Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));
@@ -336,12 +342,11 @@
             let target_collection = <Collection<T>>::get(collection_id);
 
             // TODO: implement other modes
-            ensure!(target_collection.mode == CollectionMode::NFT, "Collection type not implemented");
-
-            if target_collection.mode == CollectionMode::NFT
+            match target_collection.mode 
             {
-                Self::transfer_nft(collection_id, item_id, recipient)?;
-            }
+                CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, recipient)?,
+                _ => ()
+            };
 
             Ok(())
         }
@@ -395,13 +400,12 @@
             
             let target_collection = <Collection<T>>::get(collection_id);
 
-            // TODO: implement other modes
-            ensure!(target_collection.mode == CollectionMode::NFT, "Collection type not implemented");
-
-            if target_collection.mode == CollectionMode::NFT
+            match target_collection.mode
             {
-                Self::transfer_nft(collection_id, item_id, recipient)?;
-            }
+                CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, recipient)?,
+                // TODO: implement other modes
+                _ => ()
+            };
 
             Ok(())
         }
@@ -420,6 +424,22 @@
 
             Ok(())
         }
+
+        #[weight = 0]
+        pub fn set_offchain_schema(
+            origin,
+            collection_id: u64,
+            schema: Vec<u8>
+        ) -> DispatchResult {
+            let sender = ensure_signed(origin)?;
+            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
+            
+            let mut target_collection = <Collection<T>>::get(collection_id);
+            target_collection.offchain_schema = schema;
+            <Collection<T>>::insert(collection_id, target_collection);
+
+            Ok(())        
+        }
     }
 }
 
@@ -460,28 +480,14 @@
 
     fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool{
 
-        let mut result = false;
         let target_collection = <Collection<T>>::get(collection_id);
 
-        if target_collection.mode == CollectionMode::NFT
-        {
-            let item = <NftItemList<T>>::get(collection_id, item_id);
-            result = item.owner == subject;
-        }
-
-        if target_collection.mode == CollectionMode::Fungible
-        {
-            let item = <FungibleItemList<T>>::get(collection_id, item_id);
-            result = item.owner.contains(&subject);
-        }
-
-        if target_collection.mode == CollectionMode::ReFungible
-        {
-            let item = <ReFungibleItemList<T>>::get(collection_id, item_id);
-            result = item.owner.iter().any(|i| i.owner == subject);
+        match target_collection.mode {
+            CollectionMode::NFT(_) => <NftItemList<T>>::get(collection_id, item_id).owner == subject,
+            CollectionMode::Fungible(_) => <FungibleItemList<T>>::get(collection_id, item_id).owner.contains(&subject),
+            CollectionMode::ReFungible => <ReFungibleItemList<T>>::get(collection_id, item_id).owner.iter().any(|i| i.owner == subject),
+            CollectionMode::Invalid => false
         }
-
-        result
     }
 
     fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {
modifiedsmart_contract/ink-types-node-runtime/README.mddiffbeforeafterboth
--- a/smart_contract/ink-types-node-runtime/README.md
+++ b/smart_contract/ink-types-node-runtime/README.md
@@ -30,4 +30,67 @@
 ## Test
 ```
 cargo +nightly test
+```
+
+## UI custom types
+```
+{
+  "Schedule": {
+    "version": "u32",
+    "put_code_per_byte_cost": "Gas",
+    "grow_mem_cost": "Gas",
+    "regular_op_cost": "Gas",
+    "return_data_per_byte_cost": "Gas",
+    "event_data_per_byte_cost": "Gas",
+    "event_per_topic_cost": "Gas",
+    "event_base_cost": "Gas",
+    "call_base_cost": "Gas",
+    "instantiate_base_cost": "Gas",
+    "dispatch_base_cost": "Gas",
+    "sandbox_data_read_cost": "Gas",
+    "sandbox_data_write_cost": "Gas",
+    "transfer_cost": "Gas",
+    "instantiate_cost": "Gas",
+    "max_event_topics": "u32",
+    "max_stack_height": "u32",
+    "max_memory_pages": "u32",
+    "max_table_size": "u32",
+    "enable_println": "bool",
+    "max_subject_len": "u32"
+  },
+  "CollectionMode": {
+    "_enum": {
+      "Invalid": null,
+      "NFT": "u32",
+      "Fungible": "u32",
+      "ReFungible": null
+    }
+  },
+  "NftItemType": {
+    "Collection": "u64",
+    "Owner": "AccountId",
+    "Data": "Vec<u8>"
+  },
+  
+  
+"CollectionType": {
+    "Owner": "AccountId",
+    "Mode": "u8",
+    "ModeParam": "u32",
+    "Access": "u8",
+    "NextItemId": "u64",
+    "DecimalPoints": "u32",
+    "Name": "Vec<u16>",
+    "Description": "Vec<u16>",
+    "TokenPrefix": "Vec<u8>",
+    "CustomDataSize": "u32",
+    "OffchainSchema": "Vec<u8>",
+    "Sponsor": "AccountId",
+    "UnconfirmedSponsor": "AccountId"
+  },
+  "RawData": "Vec<u8>",
+  "Address": "AccountId",
+  "LookupSource": "AccountId",
+  "Weight": "u64"
+}
 ```
\ No newline at end of file
modifiedsmart_contract/ink-types-node-runtime/calls/lib.rsdiffbeforeafterboth
before · smart_contract/ink-types-node-runtime/calls/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]23use ink_lang as ink;45#[ink::contract(version = "0.1.0", env = NodeRuntimeTypes)]6mod calls {7    use ink_core::env;8    use ink_prelude::vec::Vec;9    use ink_prelude::*;10    use ink_types_node_runtime::{calls as runtime_calls, NodeRuntimeTypes};11    use scale::{12        Decode,13        Encode,14    };1516    #[derive(Encode, Decode)]17    pub struct NftItemType {18        pub collection: u64,19        pub owner: AccountId,20        pub data: Vec<u8>,21    }2223    /// This simple dummy contract dispatches substrate runtime calls24    #[ink(storage)]25    struct Calls {}2627    impl Calls {28        #[ink(constructor)]29        fn new(&mut self) {}3031        #[ink(message)]32        fn transfer(&self, collection_id: u64, item_id: u64, new_owner: AccountId) {33            env::println(&format!(34                "transfer invoke_runtime params {:?}, {:?}, {:?} ",35                collection_id, item_id, new_owner36            ));3738            let transfer_call = runtime_calls::transfer(collection_id, item_id, new_owner);39            // dispatch the call to the runtime40            let result = self.env().invoke_runtime(&transfer_call);4142            // report result to console43            // NOTE: println should only be used on a development chain)44            env::println(&format!("transfer invoke_runtime result {:?}", result));45        }4647        // SafeTransfer4849        #[ink(message)]50        fn approve(&self, approved: AccountId, collection_id: u64, item_id: u64) {51            env::println(&format!(52                "approve invoke_runtime params {:?}, {:?}, {:?} ",53                approved, collection_id, item_id54            ));5556            let approve_call = runtime_calls::approve(approved, collection_id, item_id);57            // dispatch the call to the runtime58            let result = self.env().invoke_runtime(&approve_call);5960            // report result to console61            // NOTE: println should only be used on a development chain)62            env::println(&format!("approve invoke_runtime result {:?}", result));63        }6465        #[ink(message)]66        fn get_approved(&self, collection_id: u64, item_id: u64) -> Vec<AccountId> {67            let mut key = vec![68                // Precomputed: Twox128("Nft")69                244, 63, 251, 230, 30, 244, 104, 116, 157, 54, 23, 172, 26, 99, 196, 183,70                // Precomputed: Twox128("ApprovedList")71                86, 163, 236, 207, 221, 111, 252, 227, 254, 40, 142, 38, 40, 224, 192, 18,72            ];7374            let key_ext = vec![75                146, 214, 40, 117, 20, 27, 72, 25, 232, 204, 175, 194, 112, 244, 140, 100,76            ];77            key.extend_from_slice(&key_ext);7879            // collection id 80            let mut collection_bytes: Vec<u8> =  collection_id.to_be_bytes().iter().cloned().collect();81            collection_bytes.reverse();82            key.extend_from_slice(&collection_bytes.as_slice());8384             // item id 85             let mut item_bytes: Vec<u8> =  item_id.to_be_bytes().iter().cloned().collect();86             item_bytes.reverse();87             key.extend_from_slice(&item_bytes.as_slice());           8889            // fetch from runtime storage90            let result = self.env().get_runtime_storage::<Vec<AccountId>>(&key[..]);91 92            match result {93                Some(Ok(accounts)) => { 94                    env::println(&format!("get_approved result {:?}", accounts));95                    accounts 96                },97                Some(Err(err)) => {98                    env::println(&format!("Error reading {:?}", err));99                    vec![]100                }101                None => {102                    env::println(&format!("No data at key {:?}", key));103                    vec![]104                }105            }106        }107108        #[ink(message)]109        fn transfer_from(&self, collection_id: u64, item_id: u64, new_owner: AccountId) {110            env::println(&format!(111                "transfer_from invoke_runtime params {:?}, {:?}, {:?} ",112                collection_id, item_id, new_owner113            ));114115            let transfer_from_call =116                runtime_calls::transfer_from(collection_id, item_id, new_owner);117            // dispatch the call to the runtime118            let result = self.env().invoke_runtime(&transfer_from_call);119120            // report result to console121            // NOTE: println should only be used on a development chain)122            env::println(&format!("transfer_from invoke_runtime result {:?}", result));123        }124125        // SafeTransferFrom126127        #[ink(message)]128        fn create_item(&self, collection_id: u64, properties: Vec<u8>) {129            env::println(&format!(130                "create_item invoke_runtime params {:?}, {:?} ",131                collection_id, properties132            ));133134            let create_item_call = runtime_calls::create_item(collection_id, properties);135            // dispatch the call to the runtime136            let result = self.env().invoke_runtime(&create_item_call);137138            // report result to console139            // NOTE: println should only be used on a development chain)140            env::println(&format!("create_item invoke_runtime result {:?}", result));141        }142143        #[ink(message)]144        fn burn_item(&self, collection_id: u64, item_id: u64) {145            env::println(&format!(146                "burn_item invoke_runtime params {:?}, {:?}",147                collection_id, item_id148            ));149150            let burn_item_call = runtime_calls::burn_item(collection_id, item_id);151            // dispatch the call to the runtime152            let result = self.env().invoke_runtime(&burn_item_call);153154            // report result to console155            // NOTE: println should only be used on a development chain)156            env::println(&format!("burn_item invoke_runtime result {:?}", result));157        }158159        // GetOwner160        #[ink(message)]161        fn get_owner(&self, collection_id: u64, token_id: u64) -> AccountId {162            let mut key = vec![163                // Precomputed: Twox128("Nft")164                244, 63, 251, 230, 30, 244, 104, 116, 157, 54, 23, 172, 26, 99, 196, 183,165                // Precomputed: Twox128("ItemList")166                116, 232, 175, 181, 237, 113, 149, 125, 139, 77, 55, 251, 115, 253, 29, 240,167            ];168169            let key_ext = vec![170                146, 214, 40, 117, 20, 27, 72, 25, 232, 204, 175, 194, 112, 244, 140, 100,171            ];172            key.extend_from_slice(&key_ext);173174            // collection id 175            let mut collection_bytes: Vec<u8> =  collection_id.to_be_bytes().iter().cloned().collect();176            collection_bytes.reverse();177            key.extend_from_slice(&collection_bytes.as_slice());178179             // token id 180             let mut token_bytes: Vec<u8> =  token_id.to_be_bytes().iter().cloned().collect();181             token_bytes.reverse();182             key.extend_from_slice(&token_bytes.as_slice());           183184            // fetch from runtime storage        185            let result = self.env().get_runtime_storage::<NftItemType>(&key[..]);186 187            match result {188                Some(Ok(item)) => { 189                    env::println(&format!("get_owner result {:?}", item.owner));190                    item.owner191                },192                Some(Err(err)) => {193                    env::println(&format!("Error reading {:?}", err));194                    AccountId::from([0u8; 32])195                }196                None => {197                    env::println(&format!("No data at key {:?}", key));198                    AccountId::from([0u8; 32])199                }200            }201        }202203        #[ink(message)]204        fn get_balance_of(&self, collection_id: u64, owner: AccountId) -> u64 {205            let mut key = vec![206                // Precomputed: Twox128("Nft")207                244, 63, 251, 230, 30, 244, 104, 116, 157, 54, 23, 172, 26, 99, 196, 183,208                // Precomputed: Twox128("Balance")209                78, 168, 234, 12, 1, 250, 164, 43, 110, 179, 68, 168, 92, 71, 179, 135,210            ];211212            let key_ext = vec![213                15, 97, 136, 0, 76, 187, 168, 28, 239, 85, 170, 23, 77, 81, 248, 159,214            ];215            key.extend_from_slice(&key_ext);216217            // collection id 218            let mut collection_bytes: Vec<u8> =  collection_id.to_be_bytes().iter().cloned().collect();219            collection_bytes.reverse();220            key.extend_from_slice(&collection_bytes.as_slice());221222             // owner223             key.extend_from_slice(&owner.encode());           224225            // fetch from runtime storage226            let result = self.env().get_runtime_storage::<u64>(&key[..]);227 228            match result {229                Some(Ok(balance)) => { 230                    env::println(&format!("get_balance_of result {:?}", balance));231                    balance232                },233                Some(Err(err)) => {234                    env::println(&format!("Error reading {:?}", err));235                    0236                }237                None => {238                    env::println(&format!("No data at key {:?}", key));239                    0240                }241            }242        }243    }244}
modifiedsmart_contract/ink-types-node-runtime/src/calls.rsdiffbeforeafterboth
--- a/smart_contract/ink-types-node-runtime/src/calls.rs
+++ b/smart_contract/ink-types-node-runtime/src/calls.rs
@@ -25,7 +25,7 @@
     T::AccountId: Member + Codec,
 {
     #[allow(non_camel_case_types)]
-    create_collection(Vec<u16>, Vec<u16>, Vec<u8>, u32),
+    create_collection(Vec<u16>, Vec<u16>, Vec<u8>, u8, u32, u32),
 
     #[allow(non_camel_case_types)]
     destroy_collection(u64),
@@ -40,19 +40,19 @@
     remove_collection_admin(u64, T::AccountId),
 
     #[allow(non_camel_case_types)]
-    create_item(u64, Vec<u8>),
+    create_item(u64, Vec<u8>, T::AccountId),
 
     #[allow(non_camel_case_types)]
     burn_item(u64, u64),
 
     #[allow(non_camel_case_types)]
-    transfer(u64, u64, T::AccountId),
+    transfer(T::AccountId, u64, u64),
 
     #[allow(non_camel_case_types)]
     nft_approve(T::AccountId, u64, u64),
 
     #[allow(non_camel_case_types)]
-    nft_transfer_from(u64, u64, T::AccountId),
+    nft_transfer_from(T::AccountId, u64, u64),
 
     #[allow(non_camel_case_types)]
     nft_safe_transfer(u64, u64, T::AccountId),
@@ -66,13 +66,17 @@
     collection_name: Vec<u16>,
     collection_description: Vec<u16>,
     token_prefix: Vec<u8>,
-    custom_data_sz: u32,
+    mode: u8,
+    decimal_points: u32,
+    custom_data_size: u32,
 ) -> Call {
     Nft::<NodeRuntimeTypes>::create_collection(
         collection_name,
         collection_description,
         token_prefix,
-        custom_data_sz,
+        mode,
+        decimal_points,
+        custom_data_size,
     )
     .into()
 }
@@ -89,8 +93,8 @@
     Nft::<NodeRuntimeTypes>::nft_transfer_from(collection_id, item_id, new_owner.into()).into()
 }
 
-pub fn create_item(collection_id: u64, properties: Vec<u8>) -> Call {
-    Nft::<NodeRuntimeTypes>::create_item(collection_id, properties).into()
+pub fn create_item(collection_id: u64, properties: Vec<u8>, owner: AccountId) -> Call {
+    Nft::<NodeRuntimeTypes>::create_item(collection_id, properties, owner).into()
 }
 
 pub fn burn_item(collection_id: u64, item_id: u64) -> Call {