From 675d1d0e13af3a76c3709573634f7f978cecfab3 Mon Sep 17 00:00:00 2001 From: str-mv Date: Mon, 03 Aug 2020 12:13:54 +0000 Subject: [PATCH] Offchain schema added --- --- a/Cargo.lock +++ b/Cargo.lock @@ -3086,6 +3086,7 @@ "frame-support", "frame-system", "parity-scale-codec", + "serde", "sp-core", "sp-io", "sp-runtime", --- 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 '] @@ -49,6 +53,7 @@ default = ['std'] std = [ 'codec/std', + "serde/std", 'frame-support/std', 'frame-system/std', 'sp-runtime/std', --- 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 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, // 256 include null escape char pub token_prefix: Vec, // 16 include null escape char pub custom_data_size: u32, + pub offchain_schema: Vec, + 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 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; pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec; @@ -101,7 +120,6 @@ pub NftItemList get(fn nft_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType; pub FungibleItemList get(fn fungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType; pub ReFungibleItemList get(fn refungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType; - 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; } @@ -132,36 +150,19 @@ collection_name: Vec, collection_description: Vec, token_prefix: Vec, - 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 >::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 @@ >::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, ::get(collection_id))); @@ -336,12 +342,11 @@ let target_collection = >::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 = >::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 + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + Self::check_owner_or_admin_permissions(collection_id, sender.clone())?; + + let mut target_collection = >::get(collection_id); + target_collection.offchain_schema = schema; + >::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 = >::get(collection_id); - if target_collection.mode == CollectionMode::NFT - { - let item = >::get(collection_id, item_id); - result = item.owner == subject; - } - - if target_collection.mode == CollectionMode::Fungible - { - let item = >::get(collection_id, item_id); - result = item.owner.contains(&subject); - } - - if target_collection.mode == CollectionMode::ReFungible - { - let item = >::get(collection_id, item_id); - result = item.owner.iter().any(|i| i.owner == subject); + match target_collection.mode { + CollectionMode::NFT(_) => >::get(collection_id, item_id).owner == subject, + CollectionMode::Fungible(_) => >::get(collection_id, item_id).owner.contains(&subject), + CollectionMode::ReFungible => >::get(collection_id, item_id).owner.iter().any(|i| i.owner == subject), + CollectionMode::Invalid => false } - - result } fn add_nft_item(item: NftItemType) -> DispatchResult { --- 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" + }, + + +"CollectionType": { + "Owner": "AccountId", + "Mode": "u8", + "ModeParam": "u32", + "Access": "u8", + "NextItemId": "u64", + "DecimalPoints": "u32", + "Name": "Vec", + "Description": "Vec", + "TokenPrefix": "Vec", + "CustomDataSize": "u32", + "OffchainSchema": "Vec", + "Sponsor": "AccountId", + "UnconfirmedSponsor": "AccountId" + }, + "RawData": "Vec", + "Address": "AccountId", + "LookupSource": "AccountId", + "Weight": "u64" +} ``` \ No newline at end of file --- a/smart_contract/ink-types-node-runtime/calls/lib.rs +++ b/smart_contract/ink-types-node-runtime/calls/lib.rs @@ -123,15 +123,14 @@ } // SafeTransferFrom - #[ink(message)] - fn create_item(&self, collection_id: u64, properties: Vec) { + fn create_item(&self, collection_id: u64, properties: Vec, owner: AccountId) { env::println(&format!( "create_item invoke_runtime params {:?}, {:?} ", collection_id, properties )); - let create_item_call = runtime_calls::create_item(collection_id, properties); + let create_item_call = runtime_calls::create_item(collection_id, properties, owner); // dispatch the call to the runtime let result = self.env().invoke_runtime(&create_item_call); --- 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, Vec, Vec, u32), + create_collection(Vec, Vec, Vec, 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), + create_item(u64, Vec, 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, collection_description: Vec, token_prefix: Vec, - custom_data_sz: u32, + mode: u8, + decimal_points: u32, + custom_data_size: u32, ) -> Call { Nft::::create_collection( collection_name, collection_description, token_prefix, - custom_data_sz, + mode, + decimal_points, + custom_data_size, ) .into() } @@ -89,8 +93,8 @@ Nft::::nft_transfer_from(collection_id, item_id, new_owner.into()).into() } -pub fn create_item(collection_id: u64, properties: Vec) -> Call { - Nft::::create_item(collection_id, properties).into() +pub fn create_item(collection_id: u64, properties: Vec, owner: AccountId) -> Call { + Nft::::create_item(collection_id, properties, owner).into() } pub fn burn_item(collection_id: u64, item_id: u64) -> Call { -- gitstuff