git.delta.rocks / unique-network / refs/commits / 55a89b2cf989

difftreelog

Refactoring

str-mv2020-07-30parent: #9f0b3c2.patch.diff
in: master

3 files changed

modifieddoc/demo_milestone1-2.mddiffbeforeafterboth
--- a/doc/demo_milestone1-2.md
+++ b/doc/demo_milestone1-2.md
@@ -52,7 +52,7 @@
 
 Before running test, open [chain state tab](https://polkadot.js.org/apps/#/chainstate) and read `nft`.`nextCollectionId` state variable, which shows how many collections were created so far. If you just started the chain, this should equal 0. 
 
-Open extrinsics tab of the [standard UI](https://polkadot.js.org/apps/#/extrinsics) and select ALICE account. Select `nft` module and `createCollection` method. Put 1 in `custom_data_sz` and run the transaction. After it is finalized, read the `nft`.`nextCollectionId` state variable. It will be equal 1.
+Open extrinsics tab of the [standard UI](https://polkadot.js.org/apps/#/extrinsics) and select ALICE account. Select `nft` module and `createCollection` method. Put 1 in `custom_data_size` and run the transaction. After it is finalized, read the `nft`.`nextCollectionId` state variable. It will be equal 1.
 
 Also, read the state variable `nft`.`collection` with ID = 1 (Because everything in NFT Palette is numbered from 1, not from 0). You will see something like this:
 
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
1#![cfg_attr(not(feature = "std"), no_std)]1#![cfg_attr(not(feature = "std"), no_std)]
22
3use codec::{Decode, Encode};
4/// A FRAME pallet template with necessary imports
5
6/// Feel free to remove or edit this file as needed.
7/// If you change the name of this file, make sure to update its references in runtime/src/lib.rs
8/// If you remove this file, you can remove those references
9
10/// For more guidance on Substrate FRAME, see the example pallet3/// For more guidance on Substrate FRAME, see the example pallet
11/// https://github.com/paritytech/substrate/blob/master/frame/example/src/lib.rs4/// https://github.com/paritytech/substrate/blob/master/frame/example/src/lib.rs
5
6use codec::{Decode, Encode};
12use frame_support::{decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure};7use frame_support::{decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure};
13use frame_system::{self as system, ensure_signed};8use frame_system::{self as system, ensure_signed};
14use sp_runtime::sp_std::prelude::Vec;9use sp_runtime::sp_std::prelude::Vec;
19#[cfg(test)]14#[cfg(test)]
20mod tests;15mod tests;
2116
17#[derive(Encode, Decode, Debug, Clone, PartialEq)]
18pub enum AccessMode {
19 Normal,
20 WhiteList,
21}
22impl Default for AccessMode { fn default() -> Self { Self::Normal } }
23
24#[derive(Encode, Decode, Debug, Eq, Clone, PartialEq)]
25pub enum CollectionMode {
26 Invalid,
27 NFT,
28 Fungible,
29 ReFungible,
30}
31impl Default for CollectionMode { fn default() -> Self { Self::Invalid } }
32
22#[derive(Encode, Decode, Default, Clone, PartialEq)]33#[derive(Encode, Decode, Default, Clone, PartialEq)]
23#[cfg_attr(feature = "std", derive(Debug))]34#[cfg_attr(feature = "std", derive(Debug))]
35pub struct Ownership<AccountId> {
36 pub owner: AccountId,
37 pub fraction: u128
38}
39
40#[derive(Encode, Decode, Default, Clone, PartialEq)]
41#[cfg_attr(feature = "std", derive(Debug))]
24pub struct CollectionType<AccountId> {42pub struct CollectionType<AccountId> {
25 pub owner: AccountId,43 pub owner: AccountId,
44 pub mode: CollectionMode,
45 pub access: AccessMode,
26 pub next_item_id: u64,46 pub next_item_id: u64,
47 pub decimal_points: u32,
27 pub name: Vec<u16>, // 64 include null escape char48 pub name: Vec<u16>, // 64 include null escape char
28 pub description: Vec<u16>, // 256 include null escape char49 pub description: Vec<u16>, // 256 include null escape char
29 pub token_prefix: Vec<u8>, // 16 include null escape char50 pub token_prefix: Vec<u8>, // 16 include null escape char
45 pub data: Vec<u8>,66 pub data: Vec<u8>,
46}67}
4768
48/// The pallet's configuration trait.69#[derive(Encode, Decode, Default, Clone, PartialEq)]
70#[cfg_attr(feature = "std", derive(Debug))]
71pub struct FungibleItemType<AccountId> {
72 pub collection: u64,
73 pub owner: Vec<AccountId>,
74 pub data: Vec<u64>,
75}
76
77#[derive(Encode, Decode, Default, Clone, PartialEq)]
78#[cfg_attr(feature = "std", derive(Debug))]
79pub struct ReFungibleItemType<AccountId> {
80 pub collection: u64,
81 pub owner: Vec<Ownership<AccountId>>,
82}
83
49pub trait Trait: system::Trait {84pub trait Trait: system::Trait {
50 // Add other types and constants required to configure this pallet.
51
52 /// The overarching event type.
53 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;85 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
54}86}
5587
56// This pallet's storage items.
57decl_storage! {88decl_storage! {
58 // It is important to update your storage name so that your pallet's
59 // storage items are isolated from other pallets.
60 trait Store for Module<T: Trait> as Nft {89 trait Store for Module<T: Trait> as Nft {
6190
62 /// Next available collection ID91 // Next available collection ID
63 pub NextCollectionID get(fn next_collection_id): u64;92 NextCollectionID get(fn next_collection_id): u64;
64 pub Collection get(fn collection): map hasher(identity) u64 => CollectionType<T::AccountId>;93 pub Collection get(fn collection): map hasher(identity) u64 => CollectionType<T::AccountId>;
65 pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;94 pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;
6695
67 /// Balance owner per collection map96 // Balance owner per collection map
68 pub Balance get(fn balance_count): map hasher(blake2_128_concat) (u64, T::AccountId) => u64;97 pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;
69 pub ApprovedList get(fn approved): map hasher(blake2_128_concat) (u64, u64) => Vec<T::AccountId>;98 pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => Vec<T::AccountId>;
7099
71 pub ItemList get(fn item_id): map hasher(blake2_128_concat) (u64, u64) => NftItemType<T::AccountId>;100 // Item collections
101 pub NftItemList get(fn nft_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;
72 pub ItemListIndex get(fn item_index): map hasher(blake2_128_concat) u64 => u64;102 pub FungibleItemList get(fn fungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;
103 pub ReFungibleItemList get(fn refungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;
104 ItemListIndex get(fn item_index): map hasher(blake2_128_concat) u64 => u64;
73105
74 pub AddressTokens get(fn address_tokens): map hasher(blake2_128_concat) (u64, T::AccountId) => Vec<u64>;106 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;
75 }107 }
76}108}
77109
78// The pallet's events
79decl_event!(110decl_event!(
80 pub enum Event<T>111 pub enum Event<T>
81 where112 where
82 AccountId = <T as system::Trait>::AccountId,113 AccountId = <T as system::Trait>::AccountId,
83 {114 {
84 Created(u64, AccountId),115 Created(u64, CollectionMode, AccountId),
85 ItemCreated(u64, u64),116 ItemCreated(u64, u64),
86 ItemDestroyed(u64, u64),117 ItemDestroyed(u64, u64),
87 }118 }
88);119);
89120
90// The pallet's dispatchable functions.
91decl_module! {121decl_module! {
92 /// The module declaration.
93 pub struct Module<T: Trait> for enum Call where origin: T::Origin {122 pub struct Module<T: Trait> for enum Call where origin: T::Origin {
94123
95 // Initializing events
96 // this is needed only if you are using events in your pallet
97 fn deposit_event() = default;124 fn deposit_event() = default;
98125
99 // Create collection of NFT with given parameters126 // Create collection of NFT with given parameters
105 collection_name: Vec<u16>,132 collection_name: Vec<u16>,
106 collection_description: Vec<u16>,133 collection_description: Vec<u16>,
107 token_prefix: Vec<u8>,134 token_prefix: Vec<u8>,
108 custom_data_sz: u32) -> DispatchResult {135 mode: CollectionMode,
136 decimal_points: u32,
137 custom_data_size: u32) -> DispatchResult {
109138
110 // Anyone can create a collection139 // Anyone can create a collection
111 let who = ensure_signed(origin)?;140 let who = ensure_signed(origin)?;
112141
142 // check type
143 ensure!((mode == CollectionMode::Fungible || mode == CollectionMode::NFT || mode == CollectionMode::ReFungible),
144 "Collection mode must be Fungible, NFT or ReFungible");
145
146 // NFT checks
147 if mode == CollectionMode::NFT
148 {
149 ensure!(decimal_points == 0, "Collection in NFT mode must have zero in decimal_points parameter");
150 }
151
152 // Fungible checks
153 if mode == CollectionMode::Fungible
154 {
155 ensure!(custom_data_size == 0, "Collection in Fungible mode must have zero in custom_data_size parameter");
156 ensure!(decimal_points != 0, "Collection in Fungible mode must have not zero in decimal_points parameter");
157 }
158
113 // check params159 // check params
160 ensure!(decimal_points < 100, "decimal_points parameter must be lower than 100");
161
114 let mut name = collection_name.to_vec();162 let mut name = collection_name.to_vec();
115 name.push(0);163 name.push(0);
116 ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");164 ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");
134 let new_collection = CollectionType {182 let new_collection = CollectionType {
135 owner: who.clone(),183 owner: who.clone(),
136 name: name,184 name: name,
185 mode: mode.clone(),
186 access: AccessMode::Normal,
137 description: description,187 description: description,
188 decimal_points: decimal_points,
138 token_prefix: prefix,189 token_prefix: prefix,
139 next_item_id: next_id,190 next_item_id: next_id,
140 custom_data_size: custom_data_sz,191 custom_data_size: custom_data_size,
141 };192 };
142193
143 // Add new collection to map194 // Add new collection to map
144 <Collection<T>>::insert(next_id, new_collection);195 <Collection<T>>::insert(next_id, new_collection);
145196
146 // call event197 // call event
147 Self::deposit_event(RawEvent::Created(next_id, who.clone()));198 Self::deposit_event(RawEvent::Created(next_id, mode.clone(), who.clone()));
148199
149 Ok(())200 Ok(())
150 }201 }
153 pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {204 pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {
154205
155 let sender = ensure_signed(origin)?;206 let sender = ensure_signed(origin)?;
156 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");207 Self::check_owner_permissions(collection_id, sender)?;
157208
158 let owner = <Collection<T>>::get(collection_id).owner;209 <AddressTokens<T>>::remove_prefix(collection_id);
210 <ApprovedList<T>>::remove_prefix(collection_id);
159 ensure!(sender == owner, "You do not own this collection");211 <Balance<T>>::remove_prefix(collection_id);
212 <ItemListIndex>::remove(collection_id);
213 <AdminList<T>>::remove(collection_id);
160 <Collection<T>>::remove(collection_id);214 <Collection<T>>::remove(collection_id);
161215
162 Ok(())216 Ok(())
166 pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {220 pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {
167221
168 let sender = ensure_signed(origin)?;222 let sender = ensure_signed(origin)?;
169 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");223 Self::check_owner_permissions(collection_id, sender)?;
170
171 let mut target_collection = <Collection<T>>::get(collection_id);224 let mut target_collection = <Collection<T>>::get(collection_id);
172 ensure!(sender == target_collection.owner, "You do not own this collection");
173
174 target_collection.owner = new_owner;225 target_collection.owner = new_owner;
175 <Collection<T>>::insert(collection_id, target_collection);226 <Collection<T>>::insert(collection_id, target_collection);
176227
181 pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {232 pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {
182233
183 let sender = ensure_signed(origin)?;234 let sender = ensure_signed(origin)?;
184 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");235 Self::check_owner_or_admin_permissions(collection_id, sender)?;
236 let mut admin_arr: Vec<T::AccountId> = Vec::new();
185237
186 let target_collection = <Collection<T>>::get(collection_id);238 if <AdminList<T>>::contains_key(collection_id)
187 let is_owner = sender == target_collection.owner;
188
189 let no_perm_mes = "You do not have permissions to modify this collection";
190 let exists = <AdminList<T>>::contains_key(collection_id);
191
192 if !is_owner
193 {239 {
194 ensure!(exists, no_perm_mes);
195 ensure!(<AdminList<T>>::get(collection_id).contains(&sender), no_perm_mes);
196 }
197
198 let mut admin_arr: Vec<T::AccountId> = Vec::new();
199 if exists
200 {
201 admin_arr = <AdminList<T>>::get(collection_id);240 admin_arr = <AdminList<T>>::get(collection_id);
202 ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");241 ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");
203 }242 }
212 pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {251 pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {
213252
214 let sender = ensure_signed(origin)?;253 let sender = ensure_signed(origin)?;
215 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");254 Self::check_owner_or_admin_permissions(collection_id, sender)?;
216255
217 let target_collection = <Collection<T>>::get(collection_id);256 if <AdminList<T>>::contains_key(collection_id)
218 let is_owner = sender == target_collection.owner;
219
220 let no_perm_mes = "You do not have permissions to modify this collection";
221 let exists = <AdminList<T>>::contains_key(collection_id);
222
223 if !is_owner
224 {257 {
225 ensure!(exists, no_perm_mes);
226 ensure!(<AdminList<T>>::get(collection_id).contains(&sender), no_perm_mes);
227 }
228
229 if exists
230 {
231 let mut admin_arr = <AdminList<T>>::get(collection_id);258 let mut admin_arr = <AdminList<T>>::get(collection_id);
232 admin_arr.retain(|i| *i != account_id);259 admin_arr.retain(|i| *i != account_id);
233 <AdminList<T>>::insert(collection_id, admin_arr);260 <AdminList<T>>::insert(collection_id, admin_arr);
237 }264 }
238265
239 #[weight = 0]266 #[weight = 0]
240 pub fn create_item(origin, collection_id: u64, properties: Vec<u8>) -> DispatchResult {267 pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {
241268
242 let sender = ensure_signed(origin)?;269 let sender = ensure_signed(origin)?;
243 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");
244270
271 // check size
245 let target_collection = <Collection<T>>::get(collection_id);272 let target_collection = <Collection<T>>::get(collection_id);
246 ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");273 ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");
247 let is_owner = sender == target_collection.owner;
248274
249 let no_perm_mes = "You do not have permissions to modify this collection";275 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
250 let exists = <AdminList<T>>::contains_key(collection_id);
251276
252 if !is_owner277 let new_balance = <Balance<T>>::get(collection_id, sender.clone()) + 1;
253 {
254 ensure!(exists, no_perm_mes);
255 ensure!(<AdminList<T>>::get(collection_id).contains(&sender), no_perm_mes);278 <Balance<T>>::insert(collection_id, sender.clone(), new_balance);
256 }
257279
258 let new_balance = <Balance<T>>::get((collection_id, sender.clone())) + 1;280 // TODO: implement other modes
259 <Balance<T>>::insert((collection_id, sender.clone()), new_balance);281 ensure!(target_collection.mode == CollectionMode::NFT, "Collection type not implemented");
260282
261 // Create new item283 if target_collection.mode == CollectionMode::NFT
284 {
285 // Create nft item
262 let new_item = NftItemType {286 let item = NftItemType {
263 collection: collection_id,287 collection: collection_id,
264 owner: sender,288 owner: owner,
265 data: properties,289 data: properties,
266 };290 };
267291
292 Self::add_nft_item(item)?;
293 }
268294
269 let current_index = <ItemListIndex>::get(collection_id)
270 .checked_add(1)
271 .expect("Item list index id error");
272
273 Self::add_token_index(collection_id, current_index, new_item.owner.clone())?;
274
275 <ItemListIndex>::insert(collection_id, current_index);
276 <ItemList<T>>::insert((collection_id, current_index), new_item);
277
278 // call event295 // call event
279 Self::deposit_event(RawEvent::ItemCreated(collection_id, current_index));296 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));
280297
281 Ok(())298 Ok(())
282 }299 }
285 pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {302 pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {
286303
287 let sender = ensure_signed(origin)?;304 let sender = ensure_signed(origin)?;
288 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");305 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
306 Self::burn_nft_item(collection_id, item_id)?;
289307
290 let target_collection = <Collection<T>>::get(collection_id);
291 let is_owner = sender == target_collection.owner;
292
293 ensure!(<ItemList<T>>::contains_key((collection_id, item_id)), "Item does not exists");
294 let item = <ItemList<T>>::get((collection_id, item_id));
295
296 if !is_owner
297 {
298 // check if item owner
299 if item.owner != sender
300 {
301 let no_perm_mes = "You do not have permissions to modify this collection";
302
303 ensure!(<AdminList<T>>::contains_key(collection_id), no_perm_mes);
304 ensure!(<AdminList<T>>::get(collection_id).contains(&sender), no_perm_mes);
305 }
306 }
307 <ItemList<T>>::remove((collection_id, item_id));
308
309 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;
310
311 // update balance
312 let new_balance = <Balance<T>>::get((collection_id, item.owner.clone())) - 1;
313 <Balance<T>>::insert((collection_id, item.owner.clone()), new_balance);
314
315 // call event308 // call event
316 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));309 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));
317310
318 Ok(())311 Ok(())
319 }312 }
320313
321 #[weight = 0]314 #[weight = 0]
322 pub fn transfer(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {315 pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {
323316
324 let sender = ensure_signed(origin)?;317 let sender = ensure_signed(origin)?;
325 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");318 Self::check_owner_or_admin_permissions(collection_id, sender)?;
326319
327 let target_collection = <Collection<T>>::get(collection_id);320 let target_collection = <Collection<T>>::get(collection_id);
328 let is_owner = sender == target_collection.owner;
329321
330 ensure!(<ItemList<T>>::contains_key((collection_id, item_id)), "Item does not exists");322 // TODO: implement other modes
331 let mut item = <ItemList<T>>::get((collection_id, item_id));323 ensure!(target_collection.mode == CollectionMode::NFT, "Collection type not implemented");
332324
333 if !is_owner325 if target_collection.mode == CollectionMode::NFT
334 {326 {
335 // check if item owner327 Self::transfer_nft(collection_id, item_id, recipient)?;
336 if item.owner != sender
337 {
338 let no_perm_mes = "You do not have permissions to modify this collection";
339
340 ensure!(<AdminList<T>>::contains_key(collection_id), no_perm_mes);
341 ensure!(<AdminList<T>>::get(collection_id).contains(&sender), no_perm_mes);
342 }
343 }328 }
344 <ItemList<T>>::remove((collection_id, item_id));
345329
346 // update balance
347 let balance_old_owner = <Balance<T>>::get((collection_id, item.owner.clone())) - 1;
348 <Balance<T>>::insert((collection_id, item.owner.clone()), balance_old_owner);
349
350 let balance_new_owner = <Balance<T>>::get((collection_id, new_owner.clone())) + 1;
351 <Balance<T>>::insert((collection_id, new_owner.clone()), balance_new_owner);
352
353 // change owner
354 let old_owner = item.owner.clone();
355 item.owner = new_owner.clone();
356 <ItemList<T>>::insert((collection_id, item_id), item);
357
358 // update index collection
359 Self::move_token_index(collection_id, item_id, old_owner, new_owner.clone())?;
360
361 // reset approved list
362 let itm: Vec<T::AccountId> = Vec::new();
363 <ApprovedList<T>>::insert((collection_id, item_id), itm);
364
365 Ok(())330 Ok(())
366 }331 }
367332
368 #[weight = 0]333 #[weight = 0]
369 pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {334 pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {
370335
371 let sender = ensure_signed(origin)?;336 let sender = ensure_signed(origin)?;
372 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");
373337
374 let target_collection = <Collection<T>>::get(collection_id);338 let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);
375 let is_owner = sender == target_collection.owner;
376
377 ensure!(<ItemList<T>>::contains_key((collection_id, item_id)), "Item does not exists");
378 let item = <ItemList<T>>::get((collection_id, item_id));
379
380 if !is_owner339 if !item_owner
381 {340 {
382 // check if item owner341 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
383 if item.owner != sender
384 {
385 let no_perm_mes = "You do not have permissions to modify this collection";
386
387 ensure!(<AdminList<T>>::contains_key(collection_id), no_perm_mes);
388 ensure!(<AdminList<T>>::get(collection_id).contains(&sender), no_perm_mes);
389 }
390 }342 }
391343
392 let list_exists = <ApprovedList<T>>::contains_key((collection_id, item_id));344 let list_exists = <ApprovedList<T>>::contains_key(collection_id, item_id);
393 if list_exists {345 if list_exists {
394346
395 let mut list = <ApprovedList<T>>::get((collection_id, item_id));347 let mut list = <ApprovedList<T>>::get(collection_id, item_id);
396 let item_contains = list.contains(&approved.clone());348 let item_contains = list.contains(&approved.clone());
397349
398 if !item_contains {350 if !item_contains {
402354
403 let mut itm = Vec::new();355 let mut itm = Vec::new();
404 itm.push(approved.clone());356 itm.push(approved.clone());
405 <ApprovedList<T>>::insert((collection_id, item_id), itm);357 <ApprovedList<T>>::insert(collection_id, item_id, itm);
406 }358 }
407359
408 Ok(())360 Ok(())
409 }361 }
410362
411 #[weight = 0]363 #[weight = 0]
412 pub fn transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {364 pub fn transfer_from(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, ) -> DispatchResult {
413365
414 let no_perm_mes = "You do not have permissions to modify this collection";366 let mut approved: bool = false;
367 let sender = ensure_signed(origin)?;
415 ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);368 let approved_list_exists = <ApprovedList<T>>::contains_key(collection_id, item_id);
416 let list_itm = <ApprovedList<T>>::get((collection_id, item_id));369 if approved_list_exists
370 {
371 let list_itm = <ApprovedList<T>>::get(collection_id, item_id);
417 ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);372 approved = list_itm.contains(&recipient.clone());
373 }
418374
419 Self::transfer(origin, collection_id, item_id, new_owner)?;375 if !approved
376 {
377 Self::check_owner_or_admin_permissions(collection_id, sender)?;
378 }
379
380 let target_collection = <Collection<T>>::get(collection_id);
420381
382 // TODO: implement other modes
383 ensure!(target_collection.mode == CollectionMode::NFT, "Collection type not implemented");
384
385 if target_collection.mode == CollectionMode::NFT
386 {
387 Self::transfer_nft(collection_id, item_id, recipient)?;
388 }
389
421 Ok(())390 Ok(())
422 }391 }
423392
424 #[weight = 0]393 #[weight = 0]
425 pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {394 pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {
426395
427 let no_perm_mes = "You do not have permissions to modify this collection";396 // let no_perm_mes = "You do not have permissions to modify this collection";
428 ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);397 // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);
429 let list_itm = <ApprovedList<T>>::get((collection_id, item_id));398 // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));
430 ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);399 // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);
431400
432 // on_nft_received call401 // // on_nft_received call
433402
434 Self::transfer(origin, collection_id, item_id, new_owner)?;403 // Self::transfer(origin, collection_id, item_id, new_owner)?;
435404
436 Ok(())405 Ok(())
437 }406 }
440409
441impl<T: Trait> Module<T> {410impl<T: Trait> Module<T> {
411
412 fn collection_exists(collection_id: u64) -> DispatchResult{
413 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");
414 Ok(())
415 }
416
417 fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {
418
419 Self::collection_exists(collection_id)?;
420
421 let target_collection = <Collection<T>>::get(collection_id);
422 ensure!(subject == target_collection.owner, "You do not own this collection");
423
424 Ok(())
425 }
426
427 fn check_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {
428
429 Self::collection_exists(collection_id)?;
430
431 let target_collection = <Collection<T>>::get(collection_id);
432 let is_owner = subject == target_collection.owner;
433
434 let no_perm_mes = "You do not have permissions to modify this collection";
435 let exists = <AdminList<T>>::contains_key(collection_id);
436
437 if !is_owner
438 {
439 ensure!(exists, no_perm_mes);
440 ensure!(<AdminList<T>>::get(collection_id).contains(&subject), no_perm_mes);
441 }
442 Ok(())
443 }
444
445 fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool{
446
447 let mut result = false;
448 let target_collection = <Collection<T>>::get(collection_id);
449
450 if target_collection.mode == CollectionMode::NFT
451 {
452 let item = <NftItemList<T>>::get(collection_id, item_id);
453 result = item.owner == subject;
454 }
455
456 if target_collection.mode == CollectionMode::Fungible
457 {
458 let item = <FungibleItemList<T>>::get(collection_id, item_id);
459 result = item.owner.contains(&subject);
460 }
461
462 if target_collection.mode == CollectionMode::ReFungible
463 {
464 let item = <ReFungibleItemList<T>>::get(collection_id, item_id);
465 result = item.owner.iter().any(|i| i.owner == subject);
466 }
467
468 result
469 }
470
471 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {
472
473 let current_index = <ItemListIndex>::get(item.collection)
474 .checked_add(1)
475 .expect("Item list index id error");
476
477 Self::add_token_index(item.collection, current_index, item.owner.clone())?;
478
479 <ItemListIndex>::insert(item.collection, current_index);
480 <NftItemList<T>>::insert(item.collection, current_index, item);
481
482 Ok(())
483 }
484
485 fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {
486
487 let item = <NftItemList<T>>::get(collection_id, item_id);
488 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;
489
490 // update balance
491 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone()).checked_sub(1).unwrap();
492 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);
493 <NftItemList<T>>::remove(collection_id, item_id);
494
495 Ok(())
496 }
497
498 fn transfer_nft(collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {
499
500 let mut item = <NftItemList<T>>::get(collection_id, item_id);
501
502 // update balance
503 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone()).checked_sub(1).unwrap();
504 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);
505
506 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone()).checked_add(1).unwrap();
507 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);
508
509 // change owner
510 let old_owner = item.owner.clone();
511 item.owner = new_owner.clone();
512 <NftItemList<T>>::insert(collection_id, item_id, item);
513
514 // update index collection
515 Self::move_token_index(collection_id, item_id, old_owner, new_owner.clone())?;
516
517 // reset approved list
518 let itm: Vec<T::AccountId> = Vec::new();
519 <ApprovedList<T>>::insert(collection_id, item_id, itm);
520
521 // remove item
522 <NftItemList<T>>::remove(collection_id, item_id);
523
524 Ok(())
525 }
526
442 fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {527 fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {
443 let list_exists = <AddressTokens<T>>::contains_key((collection_id, owner.clone()));528 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());
444 if list_exists {529 if list_exists {
445 let mut list = <AddressTokens<T>>::get((collection_id, owner.clone()));530 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());
446 let item_contains = list.contains(&item_index.clone());531 let item_contains = list.contains(&item_index.clone());
447532
448 if !item_contains {533 if !item_contains {
449 list.push(item_index.clone());534 list.push(item_index.clone());
450 }535 }
451536
452 <AddressTokens<T>>::insert((collection_id, owner.clone()), list);537 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);
453 } else {538 } else {
454 let mut itm = Vec::new();539 let mut itm = Vec::new();
455 itm.push(item_index.clone());540 itm.push(item_index.clone());
456 <AddressTokens<T>>::insert((collection_id, owner), itm);541 <AddressTokens<T>>::insert(collection_id, owner, itm);
457 }542 }
458543
459 Ok(())544 Ok(())
464 item_index: u64,549 item_index: u64,
465 owner: T::AccountId,550 owner: T::AccountId,
466 ) -> DispatchResult {551 ) -> DispatchResult {
467 let list_exists = <AddressTokens<T>>::contains_key((collection_id, owner.clone()));552 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());
468 if list_exists {553 if list_exists {
469 let mut list = <AddressTokens<T>>::get((collection_id, owner.clone()));554 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());
470 let item_contains = list.contains(&item_index.clone());555 let item_contains = list.contains(&item_index.clone());
471556
472 if item_contains {557 if item_contains {
473 list.retain(|&item| item != item_index);558 list.retain(|&item| item != item_index);
474 <AddressTokens<T>>::insert((collection_id, owner), list);559 <AddressTokens<T>>::insert(collection_id, owner, list);
475 }560 }
476 }561 }
477562
modifiedpallets/nft/src/mock.rsdiffbeforeafterboth
--- a/pallets/nft/src/mock.rs
+++ b/pallets/nft/src/mock.rs
@@ -1,14 +1,20 @@
 // Creating mock runtime here
 
 use crate::{Module, Trait};
-use frame_support::{impl_outer_origin, parameter_types, weights::Weight};
 use frame_system as system;
 use sp_core::H256;
 use sp_runtime::{
     testing::Header,
-    traits::{BlakeTwo256, IdentityLookup},
+    traits::{BlakeTwo256, IdentityLookup, Saturating},
     Perbill,
 };
+use frame_support::{
+    parameter_types, impl_outer_origin,
+    weights::{
+        constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight},
+        Weight,
+    },
+};
 
 impl_outer_origin! {
     pub enum Origin for Test {}
@@ -24,7 +30,10 @@
     pub const MaximumBlockWeight: Weight = 1024;
     pub const MaximumBlockLength: u32 = 2 * 1024;
     pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
+    pub MaximumExtrinsicWeight: Weight = AvailableBlockRatio::get()
+    .saturating_sub(Perbill::from_percent(10)) * MaximumBlockWeight::get();
 }
+
 impl system::Trait for Test {
     type Origin = Origin;
     type Call = ();
@@ -40,6 +49,11 @@
     type MaximumBlockWeight = MaximumBlockWeight;
     type MaximumBlockLength = MaximumBlockLength;
     type AvailableBlockRatio = AvailableBlockRatio;
+    type BaseCallFilter = (); 
+    type DbWeight = RocksDbWeight; 
+    type BlockExecutionWeight = BlockExecutionWeight; 
+    type ExtrinsicBaseWeight = ExtrinsicBaseWeight;
+    type MaximumExtrinsicWeight = MaximumExtrinsicWeight;
     type Version = ();
     type ModuleToIndex = ();
     type AccountData = ();