difftreelog
funfible item added
in: master
3 files changed
README.mddiffbeforeafterboth--- a/README.md
+++ b/README.md
@@ -117,6 +117,20 @@
"ReFungible": "(u32, u32)"
}
},
+ "Ownership": {
+ "Owner": "AccountId",
+ "Fraction": "u128"
+ },
+ "FungibleItemType": {
+ "Collection": "u64",
+ "Owner": "AccountId",
+ "Value": "u128"
+ },
+ "ReFungibleItemType": {
+ "Collection": "u64",
+ "Owner": "Vec<Ownership>",
+ "Data": "Vec<u8>"
+ },
"NftItemType": {
"Collection": "u64",
"Owner": "AccountId",
pallets/nft/src/lib.rsdiffbeforeafterboth--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -122,6 +122,13 @@
pub data: Vec<u8>,
}
+#[derive(Encode, Decode, Default, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Debug))]
+pub struct ApprovePermissions<AccountId> {
+ pub approved: AccountId,
+ pub amount: u64
+}
+
pub trait Trait: system::Trait {
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
@@ -138,11 +145,13 @@
pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;
pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;
- // Balance owner per collection map
+ /// Balance owner per collection map
pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;
- pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => Vec<T::AccountId>;
- // Item collections
+ /// second parameter: item id + owner account id
+ pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;
+
+ /// Item collections
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>;
@@ -248,6 +257,7 @@
let sender = ensure_signed(origin)?;
Self::check_owner_permissions(collection_id, sender)?;
+ // TODO Items remove
<AddressTokens<T>>::remove_prefix(collection_id);
<ApprovedList<T>>::remove_prefix(collection_id);
<Balance<T>>::remove_prefix(collection_id);
@@ -356,18 +366,18 @@
pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {
let sender = ensure_signed(origin)?;
-
- // check size
let target_collection = <Collection<T>>::get(collection_id);
- ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");
-
Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
// TODO: implement other modes
match target_collection.mode
{
CollectionMode::NFT(_) => {
- // Create nft item
+
+ // check size
+ ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");
+
+ // Create nft item
let item = NftItemType {
collection: collection_id,
owner: owner,
@@ -377,7 +387,24 @@
Self::add_nft_item(item)?;
},
+ CollectionMode::Fungible(_) => {
+
+ // check size
+ ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type");
+
+ let item = FungibleItemType {
+ collection: collection_id,
+ owner: owner,
+ value: (10 as u128).pow(target_collection.decimal_points)
+ };
+
+ Self::add_fungible_item(item)?;
+ },
CollectionMode::ReFungible(_, _) => {
+
+ // check size
+ ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");
+
let mut owner_list = Vec::new();
let value = (10 as u128).pow(target_collection.decimal_points);
owner_list.push(Ownership {owner: owner, fraction: value});
@@ -413,6 +440,7 @@
match target_collection.mode
{
CollectionMode::NFT(_) => Self::burn_nft_item(collection_id, item_id)?,
+ CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,
CollectionMode::ReFungible(_, _) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,
_ => ()
};
@@ -435,6 +463,7 @@
match target_collection.mode
{
CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,
+ CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,
CollectionMode::ReFungible(_, _) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,
_ => ()
};
@@ -447,26 +476,26 @@
let sender = ensure_signed(origin)?;
- let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);
- if !item_owner
- {
- Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
- }
+ // amount param stub
+ let amount = 100000000;
- let list_exists = <ApprovedList<T>>::contains_key(collection_id, item_id);
+ ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id), "Only item owner can call transfer method");
+
+ let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));
if list_exists {
- let mut list = <ApprovedList<T>>::get(collection_id, item_id);
- let item_contains = list.contains(&approved.clone());
+ let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));
+ let item_contains = list.iter().any(|i| i.approved == approved);
if !item_contains {
- list.push(approved.clone());
+ list.push(ApprovePermissions { approved: approved.clone(), amount: amount });
+ <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);
}
} else {
- let mut itm = Vec::new();
- itm.push(approved.clone());
- <ApprovedList<T>>::insert(collection_id, item_id, itm);
+ let mut list = Vec::new();
+ list.push(ApprovePermissions { approved: approved.clone(), amount: amount });
+ <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);
}
Ok(())
@@ -475,16 +504,21 @@
#[weight = 0]
pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {
- let mut approved: bool = false;
let sender = ensure_signed(origin)?;
- let approved_list_exists = <ApprovedList<T>>::contains_key(collection_id, item_id);
+ let approved_list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone()));
if approved_list_exists
{
- let list_itm = <ApprovedList<T>>::get(collection_id, item_id);
- approved = list_itm.contains(&recipient.clone());
- }
+ let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));
+ let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());
+ ensure!(opt_item.is_some(), "No approve found");
+ ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");
- if !approved
+ // remove approve
+ let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))
+ .into_iter().filter(|i| i.approved != sender.clone()).collect();
+ <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);
+ }
+ else
{
Self::check_owner_or_admin_permissions(collection_id, sender)?;
}
@@ -494,8 +528,8 @@
match target_collection.mode
{
CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, from, recipient)?,
- CollectionMode::ReFungible(_, _) => Self::transfer_refungible(collection_id, item_id, value, from, recipient)?,
- // TODO: implement other modes
+ CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,
+ CollectionMode::ReFungible(_, _) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,
_ => ()
};
@@ -537,6 +571,121 @@
impl<T: Trait> Module<T> {
+ fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {
+
+ let current_index = <ItemListIndex>::get(item.collection)
+ .checked_add(1)
+ .expect("Item list index id error");
+ let itemcopy = item.clone();
+ let owner = item.owner.clone();
+ let value = item.value as u64;
+
+ Self::add_token_index(item.collection, current_index, owner.clone())?;
+
+ <ItemListIndex>::insert(item.collection, current_index);
+ <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);
+
+ // Update balance
+ let new_balance = <Balance<T>>::get(item.collection, owner.clone()).checked_add(value).unwrap();
+ <Balance<T>>::insert(item.collection, owner.clone(), new_balance);
+
+ Ok(())
+ }
+
+ fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {
+
+ let current_index = <ItemListIndex>::get(item.collection)
+ .checked_add(1)
+ .expect("Item list index id error");
+ let itemcopy = item.clone();
+
+ let value = item.owner.first().unwrap().fraction as u64;
+ let owner = item.owner.first().unwrap().owner.clone();
+
+ Self::add_token_index(item.collection, current_index, owner.clone())?;
+
+ <ItemListIndex>::insert(item.collection, current_index);
+ <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);
+
+ // Update balance
+ let new_balance = <Balance<T>>::get(item.collection, owner.clone()).checked_add(value).unwrap();
+ <Balance<T>>::insert(item.collection, owner.clone(), new_balance);
+
+ Ok(())
+ }
+
+ fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {
+
+ let current_index = <ItemListIndex>::get(item.collection)
+ .checked_add(1)
+ .expect("Item list index id error");
+
+ let item_owner = item.owner.clone();
+ let collection_id = item.collection.clone();
+ Self::add_token_index(collection_id, current_index, item.owner.clone())?;
+
+ <ItemListIndex>::insert(collection_id, current_index);
+ <NftItemList<T>>::insert(collection_id, current_index, item);
+
+ // Update balance
+ let new_balance = <Balance<T>>::get(collection_id, item_owner.clone()).checked_add(1).unwrap();
+ <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);
+
+ Ok(())
+ }
+
+ fn burn_refungible_item(collection_id: u64, item_id: u64, owner: T::AccountId) -> DispatchResult {
+
+ let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);
+ let item = collection.owner.iter().filter(|&i| i.owner == owner).next().unwrap();
+ Self::remove_token_index(collection_id, item_id, owner.clone())?;
+
+ // remove approve list
+ <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));
+
+ // update balance
+ let new_balance = <Balance<T>>::get(collection_id, item.owner.clone()).checked_sub(item.fraction as u64).unwrap();
+ <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);
+
+
+ <ReFungibleItemList<T>>::remove(collection_id, item_id);
+
+ Ok(())
+ }
+
+ fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {
+
+ let item = <NftItemList<T>>::get(collection_id, item_id);
+ Self::remove_token_index(collection_id, item_id, item.owner.clone())?;
+
+ // remove approve list
+ <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));
+
+ // update balance
+ let new_balance = <Balance<T>>::get(collection_id, item.owner.clone()).checked_sub(1).unwrap();
+ <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);
+ <NftItemList<T>>::remove(collection_id, item_id);
+
+ Ok(())
+ }
+
+ fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {
+
+ let item = <FungibleItemList<T>>::get(collection_id, item_id);
+ Self::remove_token_index(collection_id, item_id, item.owner.clone())?;
+
+ // remove approve list
+ <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));
+
+ // update balance
+ let new_balance = <Balance<T>>::get(collection_id, item.owner.clone()).checked_sub(item.value as u64).unwrap();
+ <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);
+
+ <FungibleItemList<T>>::remove(collection_id, item_id);
+
+ Ok(())
+ }
+
fn collection_exists(collection_id: u64) -> DispatchResult{
ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");
Ok(())
@@ -582,50 +731,90 @@
}
}
- fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {
+ fn transfer_fungible(collection_id: u64, item_id: u64, value: u64, owner: T::AccountId, new_owner: T::AccountId) -> DispatchResult {
+ let full_item = <FungibleItemList<T>>::get(collection_id, item_id);
+ let amount = full_item.value;
+
+ ensure!(amount >= value.into(),"Item balance not enouth");
+
+ // update balance
+ let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone()).checked_sub(value).unwrap();
+ <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);
+
+ let mut new_owner_account_id = 0;
+ let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());
+ if new_owner_items.len() > 0 {
+ new_owner_account_id = new_owner_items[0];
+ }
+
+ let val64 = value.into();
- let current_index = <ItemListIndex>::get(item.collection)
- .checked_add(1)
- .expect("Item list index id error");
+ // transfer
+ if amount == val64 && new_owner_account_id == 0
+ {
+ // change owner
+ // new owner do not have account
+ let mut new_full_item = full_item.clone();
+ new_full_item.owner = new_owner.clone();
+ <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);
- let value = item.owner.first().unwrap().fraction as u64;
- let owner = item.owner.first().unwrap().owner.clone();
+ // update balance
+ let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone()).checked_add(value).unwrap();
+ <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);
- Self::add_token_index(item.collection, current_index, owner.clone())?;
+ // update index collection
+ Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;
+ }
+ else
+ {
+ let mut new_full_item = full_item.clone();
+ new_full_item.value -= val64;
- <ItemListIndex>::insert(item.collection, current_index);
- <ReFungibleItemList<T>>::insert(item.collection, current_index, item);
-
- // Update balance
- let new_balance = <Balance<T>>::get(item.collection, owner.clone()).checked_add(value).unwrap();
- <Balance<T>>::insert(item.collection, owner.clone(), new_balance);
+ // separate amount
+ if new_owner_account_id > 0 {
+
+ // new owner has account
+ let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);
+ item.value += val64;
+
+ // update balance
+ let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone()).checked_add(value).unwrap();
+ <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);
- Ok(())
- }
+ <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);
+ }
+ else
+ {
+ // new owner do not have account
+ let item = FungibleItemType {
+ collection: collection_id,
+ owner: new_owner.clone(),
+ value: val64
+ };
- fn burn_refungible_item(collection_id: u64, item_id: u64, owner: T::AccountId) -> DispatchResult {
-
- let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);
- let item = collection.owner.iter().filter(|&i| i.owner == owner).next().unwrap();
- Self::remove_token_index(collection_id, item_id, owner)?;
+ Self::add_fungible_item(item)?;
+ }
- // update balance
- let new_balance = <Balance<T>>::get(collection_id, item.owner.clone()).checked_sub(item.fraction as u64).unwrap();
- <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);
+ if amount == val64{
+ Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;
+
+ // remove approve list
+ <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));
+ <FungibleItemList<T>>::remove(collection_id, item_id);
+ }
- // TODO
- <ReFungibleItemList<T>>::remove(collection_id, item_id);
+ <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);
+ }
Ok(())
}
fn transfer_refungible(collection_id: u64, item_id: u64, value: u64, owner: T::AccountId, new_owner: T::AccountId) -> DispatchResult {
-
let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);
let item = full_item.owner.iter().filter(|i| i.owner == owner).next().unwrap();
let amount = item.fraction;
- ensure!(amount < value.into(),"Item balance not enouth");
+ ensure!(amount >= value.into(),"Item balance not enouth");
// update balance
let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone()).checked_sub(value).unwrap();
@@ -636,9 +825,10 @@
let old_owner = item.owner.clone();
let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);
+ let val64 = value.into();
// transfer
- if amount == value.into() && !new_owner_has_account
+ if amount == val64 && !new_owner_has_account
{
// change owner
// new owner do not have account
@@ -652,17 +842,17 @@
else
{
let mut new_full_item = full_item.clone();
- new_full_item.owner.iter_mut().find(|i| i.owner == owner).unwrap().fraction -= amount;
+ new_full_item.owner.iter_mut().find(|i| i.owner == owner).unwrap().fraction -= val64;
// separate amount
if new_owner_has_account {
// new owner has account
- new_full_item.owner.iter_mut().find(|i| i.owner == new_owner).unwrap().fraction += amount;
+ new_full_item.owner.iter_mut().find(|i| i.owner == new_owner).unwrap().fraction += val64;
}
else
{
// new owner do not have account
- new_full_item.owner.push(Ownership { owner: new_owner.clone(), fraction: amount});
+ new_full_item.owner.push(Ownership { owner: new_owner.clone(), fraction: val64});
Self::add_token_index(collection_id, item_id, new_owner.clone())?;
}
@@ -671,38 +861,7 @@
Ok(())
}
-
- fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {
-
- let current_index = <ItemListIndex>::get(item.collection)
- .checked_add(1)
- .expect("Item list index id error");
-
- Self::add_token_index(item.collection, current_index, item.owner.clone())?;
-
- <ItemListIndex>::insert(item.collection, current_index);
- <NftItemList<T>>::insert(item.collection, current_index, item);
- // Update balance
- let new_balance = <Balance<T>>::get(item.collection, item.owner.clone()).checked_add(1).unwrap();
- <Balance<T>>::insert(item.collection_id, item.owner.clone(), new_balance);
-
- Ok(())
- }
-
- fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {
-
- let item = <NftItemList<T>>::get(collection_id, item_id);
- Self::remove_token_index(collection_id, item_id, item.owner.clone())?;
-
- // update balance
- let new_balance = <Balance<T>>::get(collection_id, item.owner.clone()).checked_sub(1).unwrap();
- <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);
- <NftItemList<T>>::remove(collection_id, item_id);
-
- Ok(())
- }
-
fn transfer_nft(collection_id: u64, item_id: u64, sender: T::AccountId, new_owner: T::AccountId) -> DispatchResult {
let mut item = <NftItemList<T>>::get(collection_id, item_id);
@@ -722,12 +881,10 @@
<NftItemList<T>>::insert(collection_id, item_id, item);
// update index collection
- Self::move_token_index(collection_id, item_id, old_owner, new_owner.clone())?;
+ Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;
// reset approved list
- let itm: Vec<T::AccountId> = Vec::new();
- <ApprovedList<T>>::insert(collection_id, item_id, itm);
-
+ <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));
Ok(())
}
pallets/nft/src/tests.rsdiffbeforeafterboth1// Tests to be written here2use crate::mock::*;3use frame_support::{assert_noop, assert_ok};45#[test]6fn create_collection_test() {7 new_test_ext().execute_with(|| {8 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();9 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();10 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();1112 let size = 1024;13 let origin1 = Origin::signed(1);14 assert_ok!(TemplateModule::create_collection(15 origin1.clone(),16 col_name1.clone(),17 col_desc1.clone(),18 token_prefix1.clone(),19 size20 ));21 assert_eq!(TemplateModule::collection(1).owner, 1);22 });23}2425#[test]26fn change_collection_owner() {27 new_test_ext().execute_with(|| {28 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();29 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();30 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();3132 let size = 1024;33 let origin1 = Origin::signed(1);3435 assert_ok!(TemplateModule::create_collection(36 origin1.clone(),37 col_name1.clone(),38 col_desc1.clone(),39 token_prefix1.clone(),40 size41 ));42 assert_ok!(TemplateModule::change_collection_owner(43 origin1.clone(),44 1,45 246 ));47 assert_eq!(TemplateModule::collection(1).owner, 2);48 });49}5051#[test]52fn destroy_collection() {53 new_test_ext().execute_with(|| {54 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();55 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();56 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();5758 let size = 1024;59 let origin1 = Origin::signed(1);6061 assert_ok!(TemplateModule::create_collection(62 origin1.clone(),63 col_name1.clone(),64 col_desc1.clone(),65 token_prefix1.clone(),66 size67 ));68 assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1));69 });70}7172#[test]73fn create_item() {74 new_test_ext().execute_with(|| {75 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();76 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();77 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();7879 let size = 1024;80 let origin1 = Origin::signed(1);81 let origin2 = Origin::signed(2);8283 assert_ok!(TemplateModule::create_collection(84 origin1.clone(),85 col_name1.clone(),86 col_desc1.clone(),87 token_prefix1.clone(),88 size89 ));90 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));91 assert_ok!(TemplateModule::create_item(92 origin2.clone(),93 1,94 [1, 1, 1].to_vec()95 ));9697 // check balance (collection with id = 1, user id = 2)98 assert_eq!(TemplateModule::balance_count((1, 2)), 1);99 });100}101102#[test]103fn burn_item() {104 new_test_ext().execute_with(|| {105 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();106 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();107 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();108109 let size = 1024;110 let origin1 = Origin::signed(1);111 let origin2 = Origin::signed(2);112113 assert_ok!(TemplateModule::create_collection(114 origin1.clone(),115 col_name1.clone(),116 col_desc1.clone(),117 token_prefix1.clone(),118 size119 ));120 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));121 assert_ok!(TemplateModule::create_item(122 origin2.clone(),123 1,124 [1, 1, 1].to_vec()125 ));126127 // check balance (collection with id = 1, user id = 2)128 assert_eq!(TemplateModule::balance_count((1, 2)), 1);129130 // burn item131 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));132 assert_noop!(133 TemplateModule::burn_item(origin1.clone(), 1, 1),134 "Item does not exists"135 );136137 assert_eq!(TemplateModule::balance_count((1, 1)), 0);138 });139}140141#[test]142fn add_collection_admin() {143 new_test_ext().execute_with(|| {144 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();145 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();146 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();147148 let size = 1024;149 let origin1 = Origin::signed(1);150 let origin2 = Origin::signed(2);151 let origin3 = Origin::signed(3);152153 assert_ok!(TemplateModule::create_collection(154 origin1.clone(),155 col_name1.clone(),156 col_desc1.clone(),157 token_prefix1.clone(),158 size159 ));160 assert_ok!(TemplateModule::create_collection(161 origin2.clone(),162 col_name1.clone(),163 col_desc1.clone(),164 token_prefix1.clone(),165 size166 ));167 assert_ok!(TemplateModule::create_collection(168 origin3.clone(),169 col_name1.clone(),170 col_desc1.clone(),171 token_prefix1.clone(),172 size173 ));174175 assert_eq!(TemplateModule::collection(1).owner, 1);176 assert_eq!(TemplateModule::collection(2).owner, 2);177 assert_eq!(TemplateModule::collection(3).owner, 3);178179 // collection admin180 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));181 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 3));182183 assert_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);184 assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), true);185 });186}187188#[test]189fn remove_collection_admin() {190 new_test_ext().execute_with(|| {191 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();192 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();193 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();194195 let size = 1024;196 let origin1 = Origin::signed(1);197 let origin2 = Origin::signed(2);198 let origin3 = Origin::signed(3);199200 assert_ok!(TemplateModule::create_collection(201 origin1.clone(),202 col_name1.clone(),203 col_desc1.clone(),204 token_prefix1.clone(),205 size206 ));207 assert_ok!(TemplateModule::create_collection(208 origin2.clone(),209 col_name1.clone(),210 col_desc1.clone(),211 token_prefix1.clone(),212 size213 ));214 assert_ok!(TemplateModule::create_collection(215 origin3.clone(),216 col_name1.clone(),217 col_desc1.clone(),218 token_prefix1.clone(),219 size220 ));221222 assert_eq!(TemplateModule::collection(1).owner, 1);223 assert_eq!(TemplateModule::collection(2).owner, 2);224 assert_eq!(TemplateModule::collection(3).owner, 3);225226 // collection admin227 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));228 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 3));229230 assert_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);231 assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), true);232233 // remove admin234 assert_ok!(TemplateModule::remove_collection_admin(235 origin2.clone(),236 1,237 3238 ));239 assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), false);240 });241}242243#[test]244fn balance_of() {245 new_test_ext().execute_with(|| {246 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();247 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();248 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();249250 let size = 1024;251 let origin1 = Origin::signed(1);252 let origin2 = Origin::signed(2);253 let origin3 = Origin::signed(3);254255 assert_ok!(TemplateModule::create_collection(256 origin1.clone(),257 col_name1.clone(),258 col_desc1.clone(),259 token_prefix1.clone(),260 size261 ));262 assert_ok!(TemplateModule::create_collection(263 origin2.clone(),264 col_name1.clone(),265 col_desc1.clone(),266 token_prefix1.clone(),267 size268 ));269 assert_ok!(TemplateModule::create_collection(270 origin3.clone(),271 col_name1.clone(),272 col_desc1.clone(),273 token_prefix1.clone(),274 size275 ));276277 assert_eq!(TemplateModule::collection(1).owner, 1);278 assert_eq!(TemplateModule::collection(2).owner, 2);279 assert_eq!(TemplateModule::collection(3).owner, 3);280281 // check balance before282 assert_eq!(TemplateModule::balance_count((1, 1)), 0);283284 // create item285 assert_ok!(TemplateModule::create_item(286 origin1.clone(),287 1,288 [1, 1, 1].to_vec()289 ));290291 // check balance (collection with id = 1, user id = 2)292 assert_eq!(TemplateModule::balance_count((1, 1)), 1);293 assert_eq!(TemplateModule::item_id((1, 1)).owner, 1);294 });295}296297#[test]298fn transfer() {299 new_test_ext().execute_with(|| {300 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();301 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();302 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();303304 let size = 1024;305 let origin1 = Origin::signed(1);306 let origin2 = Origin::signed(2);307 let origin3 = Origin::signed(3);308309 assert_ok!(TemplateModule::create_collection(310 origin1.clone(),311 col_name1.clone(),312 col_desc1.clone(),313 token_prefix1.clone(),314 size315 ));316 assert_ok!(TemplateModule::create_collection(317 origin2.clone(),318 col_name1.clone(),319 col_desc1.clone(),320 token_prefix1.clone(),321 size322 ));323 assert_ok!(TemplateModule::create_collection(324 origin3.clone(),325 col_name1.clone(),326 col_desc1.clone(),327 token_prefix1.clone(),328 size329 ));330331 assert_eq!(TemplateModule::collection(1).owner, 1);332 assert_eq!(TemplateModule::collection(2).owner, 2);333 assert_eq!(TemplateModule::collection(3).owner, 3);334335 // create item336 assert_ok!(TemplateModule::create_item(337 origin1.clone(),338 1,339 [1, 1, 1].to_vec()340 ));341342 // transfer343 assert_ok!(TemplateModule::transfer(origin1.clone(), 1, 1, 2));344 assert_eq!(TemplateModule::item_id((1, 1)).owner, 2);345346 // balance_of check347 assert_eq!(TemplateModule::balance_count((1, 1)), 0);348 assert_eq!(TemplateModule::balance_count((1, 2)), 1);349 });350}351352#[test]353fn approve() {354 new_test_ext().execute_with(|| {355 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();356 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();357 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();358359 let size = 1024;360 let origin1 = Origin::signed(1);361 let origin2 = Origin::signed(2);362 let origin3 = Origin::signed(3);363364 assert_ok!(TemplateModule::create_collection(365 origin1.clone(),366 col_name1.clone(),367 col_desc1.clone(),368 token_prefix1.clone(),369 size370 ));371 assert_ok!(TemplateModule::create_collection(372 origin2.clone(),373 col_name1.clone(),374 col_desc1.clone(),375 token_prefix1.clone(),376 size377 ));378 assert_ok!(TemplateModule::create_collection(379 origin3.clone(),380 col_name1.clone(),381 col_desc1.clone(),382 token_prefix1.clone(),383 size384 ));385386 assert_eq!(TemplateModule::collection(1).owner, 1);387 assert_eq!(TemplateModule::collection(2).owner, 2);388 assert_eq!(TemplateModule::collection(3).owner, 3);389390 // create item391 assert_ok!(TemplateModule::create_item(392 origin1.clone(),393 1,394 [1, 1, 1].to_vec()395 ));396397 // approve398 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));399 assert_eq!(TemplateModule::approved((1, 1)).contains(&2), true);400 });401}402403#[test]404fn get_approved() {405 new_test_ext().execute_with(|| {406 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();407 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();408 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();409410 let size = 1024;411 let origin1 = Origin::signed(1);412 let origin2 = Origin::signed(2);413 let origin3 = Origin::signed(3);414415 assert_ok!(TemplateModule::create_collection(416 origin1.clone(),417 col_name1.clone(),418 col_desc1.clone(),419 token_prefix1.clone(),420 size421 ));422 assert_ok!(TemplateModule::create_collection(423 origin2.clone(),424 col_name1.clone(),425 col_desc1.clone(),426 token_prefix1.clone(),427 size428 ));429 assert_ok!(TemplateModule::create_collection(430 origin3.clone(),431 col_name1.clone(),432 col_desc1.clone(),433 token_prefix1.clone(),434 size435 ));436437 assert_eq!(TemplateModule::collection(1).owner, 1);438 assert_eq!(TemplateModule::collection(2).owner, 2);439 assert_eq!(TemplateModule::collection(3).owner, 3);440441 // create item442 assert_ok!(TemplateModule::create_item(443 origin1.clone(),444 1,445 [1, 1, 1].to_vec()446 ));447448 // approve449 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));450 assert_eq!(TemplateModule::approved((1, 1)).contains(&2), true);451 });452}453454#[test]455fn transfer_from() {456 new_test_ext().execute_with(|| {457 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();458 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();459 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();460461 let size = 1024;462 let origin1 = Origin::signed(1);463 let origin2 = Origin::signed(2);464 let origin3 = Origin::signed(3);465466 assert_ok!(TemplateModule::create_collection(467 origin1.clone(),468 col_name1.clone(),469 col_desc1.clone(),470 token_prefix1.clone(),471 size472 ));473 assert_ok!(TemplateModule::create_collection(474 origin2.clone(),475 col_name1.clone(),476 col_desc1.clone(),477 token_prefix1.clone(),478 size479 ));480 assert_ok!(TemplateModule::create_collection(481 origin3.clone(),482 col_name1.clone(),483 col_desc1.clone(),484 token_prefix1.clone(),485 size486 ));487488 assert_eq!(TemplateModule::collection(1).owner, 1);489 assert_eq!(TemplateModule::collection(2).owner, 2);490 assert_eq!(TemplateModule::collection(3).owner, 3);491492 // create item493 assert_ok!(TemplateModule::create_item(494 origin1.clone(),495 1,496 [1, 1, 1].to_vec()497 ));498499 // approve500 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));501 assert_ok!(TemplateModule::transfer_from(origin1.clone(), 1, 1, 2));502 });503}504505#[test]506fn index_list() {507 new_test_ext().execute_with(|| {508 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();509 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();510 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();511512 let size = 1024;513 let origin1 = Origin::signed(1);514 let origin2 = Origin::signed(2);515 let origin3 = Origin::signed(3);516517 assert_ok!(TemplateModule::create_collection(518 origin1.clone(),519 col_name1.clone(),520 col_desc1.clone(),521 token_prefix1.clone(),522 size523 ));524 assert_ok!(TemplateModule::create_collection(525 origin2.clone(),526 col_name1.clone(),527 col_desc1.clone(),528 token_prefix1.clone(),529 size530 ));531 assert_ok!(TemplateModule::create_collection(532 origin3.clone(),533 col_name1.clone(),534 col_desc1.clone(),535 token_prefix1.clone(),536 size537 ));538539 assert_eq!(TemplateModule::collection(1).owner, 1);540 assert_eq!(TemplateModule::collection(2).owner, 2);541 assert_eq!(TemplateModule::collection(3).owner, 3);542 // create items543 assert_ok!(TemplateModule::create_item(544 origin1.clone(),545 1,546 [1, 1, 1].to_vec()547 ));548 assert_ok!(TemplateModule::create_item(549 origin1.clone(),550 1,551 [1, 1, 2].to_vec()552 ));553 assert_ok!(TemplateModule::create_item(554 origin1.clone(),555 1,556 [1, 2, 3].to_vec()557 ));558 assert_eq!(TemplateModule::address_tokens((1, 1)).len(), 3);559 // burn one560 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 2));561 assert_eq!(TemplateModule::address_tokens((1, 1)).len(), 2);562 // burn another one563 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 3));564 assert_eq!(TemplateModule::address_tokens((1, 1))[0], 1);565 });566}