difftreelog
Merge branch 'develop' into feature/NFTPAR-288
in: master
25 files changed
pallets/nft/src/lib.rsdiffbeforeafterboth323 CollectionNotFound,323 CollectionNotFound,324 /// Item not exists.324 /// Item not exists.325 TokenNotFound,325 TokenNotFound,326 /// Admin not found327 AdminNotFound,326 /// Arithmetic calculation overflow.328 /// Arithmetic calculation overflow.327 NumOverflow, 329 NumOverflow, 328 /// Account already has admin role.330 /// Account already has admin role.426 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;428 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;427429428 /// Tokens transfer baskets430 /// Tokens transfer baskets429 pub CreateItemBasket get(fn create_item_basket): map hasher(identity) CollectionId => T::BlockNumber;431 pub CreateItemBasket get(fn create_item_basket): map hasher(twox_64_concat) (CollectionId, T::AccountId) => T::BlockNumber;430 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;432 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;431 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;433 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;432 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;434 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;812814813 let sender = ensure_signed(origin)?;815 let sender = ensure_signed(origin)?;814 Self::check_owner_or_admin_permissions(collection_id, sender)?;816 Self::check_owner_or_admin_permissions(collection_id, sender)?;817 ensure!(<AdminList<T>>::contains_key(collection_id), Error::<T>::AdminNotFound);815818816 if <AdminList<T>>::contains_key(collection_id)819 let mut admin_arr = <AdminList<T>>::get(collection_id);817 {818 let mut admin_arr = <AdminList<T>>::get(collection_id);819 admin_arr.retain(|i| *i != account_id);820 admin_arr.retain(|i| *i != account_id);820 <AdminList<T>>::insert(collection_id, admin_arr);821 <AdminList<T>>::insert(collection_id, admin_arr);821 }822822823 Ok(())823 Ok(())824 }824 }1009 {1009 {1010 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1010 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1011 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1011 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1012 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1012 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, &sender)?,1013 _ => ()1013 _ => ()1014 };1014 };10151015109210921093 let sender = ensure_signed(origin)?;1093 let sender = ensure_signed(origin)?;109410941095 Self::collection_exists(collection_id)?;1096 Self::token_exists(collection_id, item_id, &sender)?;10971095 // Transfer permissions check1098 // Transfer permissions check1096 let target_collection = <Collection<T>>::get(collection_id);1099 let target_collection = <Collection<T>>::get(collection_id);1097 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1100 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1161 }1164 }116211651163 // Reduce approval by transferred amount or remove if remaining approval drops to 01166 // Reduce approval by transferred amount or remove if remaining approval drops to 01164 if approval - value > 0 {1167 if approval.checked_sub(value).unwrap_or(0) > 0 {1165 <Allowances<T>>::insert(collection_id, (item_id, &from, &recipient), approval - value);1168 <Allowances<T>>::insert(collection_id, (item_id, &from, &recipient), approval - value);1166 }1169 }1167 else {1170 else {1216 let sender = ensure_signed(origin)?;1219 let sender = ensure_signed(origin)?;1217 1220 1218 Self::collection_exists(collection_id)?;1221 Self::collection_exists(collection_id)?;1219 1222 Self::token_exists(collection_id, item_id, &sender)?;12231220 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1224 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);122112251225 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1229 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1226 Error::<T>::NoPermission);1230 Error::<T>::NoPermission);122712311228 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12291230 match target_collection.mode1232 match target_collection.mode1231 {1233 {1232 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1234 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1320 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1322 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;132113231322 // check schema limit1324 // check schema limit1323 ensure!(schema.len() as u32 > ChainLimit::get().const_on_chain_schema_limit, "");1325 ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");132413261325 let mut target_collection = <Collection<T>>::get(collection_id);1327 let mut target_collection = <Collection<T>>::get(collection_id);1326 target_collection.const_on_chain_schema = schema;1328 target_collection.const_on_chain_schema = schema;1351 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1353 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;135213541353 // check schema limit1355 // check schema limit1354 ensure!(schema.len() as u32 > ChainLimit::get().variable_on_chain_schema_limit, "");1356 ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");135513571356 let mut target_collection = <Collection<T>>::get(collection_id);1358 let mut target_collection = <Collection<T>>::get(collection_id);1357 target_collection.variable_on_chain_schema = schema;1359 target_collection.variable_on_chain_schema = schema;1677 let value = item.owner.first().unwrap().fraction;1679 let value = item.owner.first().unwrap().fraction;1678 let owner = item.owner.first().unwrap().owner.clone();1680 let owner = item.owner.first().unwrap().owner.clone();167916811680 Self::add_token_index(collection_id, current_index, owner.clone())?;1682 Self::add_token_index(collection_id, current_index, &owner)?;168116831682 <ItemListIndex>::insert(collection_id, current_index);1684 <ItemListIndex>::insert(collection_id, current_index);1683 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);1685 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);168416861685 // Update balance1687 // Update balance1686 let new_balance = <Balance<T>>::get(collection_id, owner.clone())1688 let new_balance = <Balance<T>>::get(collection_id, &owner)1687 .checked_add(value)1689 .checked_add(value)1688 .ok_or(Error::<T>::NumOverflow)?;1690 .ok_or(Error::<T>::NumOverflow)?;1689 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);1691 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);1697 .ok_or(Error::<T>::NumOverflow)?;1699 .ok_or(Error::<T>::NumOverflow)?;169817001699 let item_owner = item.owner.clone();1701 let item_owner = item.owner.clone();1700 Self::add_token_index(collection_id, current_index, item.owner.clone())?;1702 Self::add_token_index(collection_id, current_index, &item.owner)?;170117031702 <ItemListIndex>::insert(collection_id, current_index);1704 <ItemListIndex>::insert(collection_id, current_index);1703 <NftItemList<T>>::insert(collection_id, current_index, item);1705 <NftItemList<T>>::insert(collection_id, current_index, item);1714 fn burn_refungible_item(1716 fn burn_refungible_item(1715 collection_id: CollectionId,1717 collection_id: CollectionId,1716 item_id: TokenId,1718 item_id: TokenId,1717 owner: T::AccountId,1719 owner: &T::AccountId,1718 ) -> DispatchResult {1720 ) -> DispatchResult {1719 ensure!(1721 ensure!(1720 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1722 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1721 Error::<T>::TokenNotFound1723 Error::<T>::TokenNotFound1722 );1724 );1723 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1725 let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id);1724 let item = collection1726 let rft_balance = token1725 .owner1727 .owner1726 .iter()1728 .iter()1727 .filter(|&i| i.owner == owner)1729 .filter(|&i| i.owner == *owner)1728 .next()1730 .next()1729 .unwrap();1731 .unwrap();1730 Self::remove_token_index(collection_id, item_id, owner.clone())?;1732 Self::remove_token_index(collection_id, item_id, owner)?;173117331732 // update balance1734 // update balance1733 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1735 let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.clone())1734 .checked_sub(item.fraction)1736 .checked_sub(rft_balance.fraction)1735 .ok_or(Error::<T>::NumOverflow)?;1737 .ok_or(Error::<T>::NumOverflow)?;1736 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1738 <Balance<T>>::insert(collection_id, rft_balance.owner.clone(), new_balance);173717391738 <ReFungibleItemList<T>>::remove(collection_id, item_id);1740 // Re-create owners list with sender removed1741 let index = token1742 .owner1743 .iter()1744 .position(|i| i.owner == *owner)1745 .unwrap();1746 token.owner.remove(index);1747 let owner_count = token.owner.len();173917481749 // Burn the token completely if this was the last (only) owner1750 if owner_count == 0 {1751 <ReFungibleItemList<T>>::remove(collection_id, item_id);1752 }1753 else {1754 <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1755 }17561740 Ok(())1757 Ok(())1741 }1758 }174217591746 Error::<T>::TokenNotFound1763 Error::<T>::TokenNotFound1747 );1764 );1748 let item = <NftItemList<T>>::get(collection_id, item_id);1765 let item = <NftItemList<T>>::get(collection_id, item_id);1749 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;1766 Self::remove_token_index(collection_id, item_id, &item.owner)?;175017671751 // update balance1768 // update balance1752 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1769 let new_balance = <Balance<T>>::get(collection_id, &item.owner)1753 .checked_sub(1)1770 .checked_sub(1)1754 .ok_or(Error::<T>::NumOverflow)?;1771 .ok_or(Error::<T>::NumOverflow)?;1755 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1772 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1858 Ok(())1875 Ok(())1859 }1876 }186018771878 /// Check if token exists. In case of Fungible, check if there is an entry for 1879 /// the owner in fungible balances double map1880 fn token_exists(1881 collection_id: CollectionId,1882 item_id: TokenId,1883 owner: &T::AccountId1884 ) -> DispatchResult {1885 let target_collection = <Collection<T>>::get(collection_id);1886 let exists = match target_collection.mode1887 {1888 CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),1889 CollectionMode::Fungible(_) => <FungibleItemList<T>>::contains_key(collection_id, owner),1890 CollectionMode::ReFungible(_) => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1891 _ => false1892 };18931894 ensure!(exists == true, Error::<T>::TokenNotFound);1895 Ok(())1896 }18971861 fn transfer_fungible(1898 fn transfer_fungible(1862 collection_id: CollectionId,1899 collection_id: CollectionId,1863 value: u128,1900 value: u128,1864 owner: &T::AccountId,1901 owner: &T::AccountId,1865 recipient: &T::AccountId,1902 recipient: &T::AccountId,1866 ) -> DispatchResult {1903 ) -> DispatchResult {1867 ensure!(1904 Self::token_exists(collection_id, 0, owner)?;1868 <FungibleItemList<T>>::contains_key(collection_id, owner),1869 Error::<T>::TokenNotFound1870 );187119051872 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1906 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1873 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);1907 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);1897 owner: T::AccountId,1931 owner: T::AccountId,1898 new_owner: T::AccountId,1932 new_owner: T::AccountId,1899 ) -> DispatchResult {1933 ) -> DispatchResult {1900 ensure!(1934 Self::token_exists(collection_id, item_id, &owner)?;1901 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1902 Error::<T>::TokenNotFound1903 );190419351905 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1936 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1906 let item = full_item1937 let item = full_item1941 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1972 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);194219731943 // update index collection1974 // update index collection1944 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1975 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;1945 } else {1976 } else {1946 let mut new_full_item = full_item.clone();1977 let mut new_full_item = full_item.clone();1947 new_full_item1978 new_full_item1966 owner: new_owner.clone(),1997 owner: new_owner.clone(),1967 fraction: value,1998 fraction: value,1968 });1999 });1969 Self::add_token_index(collection_id, item_id, new_owner.clone())?;2000 Self::add_token_index(collection_id, item_id, &new_owner)?;1970 }2001 }197120021972 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2003 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1981 sender: T::AccountId,2012 sender: T::AccountId,1982 new_owner: T::AccountId,2013 new_owner: T::AccountId,1983 ) -> DispatchResult {2014 ) -> DispatchResult {1984 ensure!(2015 Self::token_exists(collection_id, item_id, &sender)?;1985 <NftItemList<T>>::contains_key(collection_id, item_id),1986 Error::<T>::TokenNotFound1987 );198820161989 let mut item = <NftItemList<T>>::get(collection_id, item_id);2017 let mut item = <NftItemList<T>>::get(collection_id, item_id);199020182010 <NftItemList<T>>::insert(collection_id, item_id, item);2038 <NftItemList<T>>::insert(collection_id, item_id, item);201120392012 // update index collection2040 // update index collection2013 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;2041 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;201420422015 Ok(())2043 Ok(())2016 }2044 }2017 2045 2018 fn item_exists(2019 collection_id: CollectionId,2020 item_id: TokenId,2021 mode: &CollectionMode2022 ) -> DispatchResult {2023 match mode {2024 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2025 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2026 _ => ()2027 };2028 2029 Ok(())2030 }20312032 fn set_re_fungible_variable_data(2046 fn set_re_fungible_variable_data(2033 collection_id: CollectionId,2047 collection_id: CollectionId,2034 item_id: TokenId,2048 item_id: TokenId,2090 .unwrap();2104 .unwrap();209121052092 let item_owner = item.owner.clone();2106 let item_owner = item.owner.clone();2093 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();2107 Self::add_token_index(collection_id, current_index, &item.owner).unwrap();209421082095 <ItemListIndex>::insert(collection_id, current_index);2109 <ItemListIndex>::insert(collection_id, current_index);209621102097 // Update balance2111 // Update balance2098 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2112 let new_balance = <Balance<T>>::get(collection_id, &item_owner)2099 .checked_add(1)2113 .checked_add(1)2100 .unwrap();2114 .unwrap();2101 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2115 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2106 .checked_add(1)2120 .checked_add(1)2107 .unwrap();2121 .unwrap();210821222109 Self::add_token_index(collection_id, current_index, (*owner).clone()).unwrap();2123 Self::add_token_index(collection_id, current_index, owner).unwrap();211021242111 <ItemListIndex>::insert(collection_id, current_index);2125 <ItemListIndex>::insert(collection_id, current_index);211221262125 let value = item.owner.first().unwrap().fraction;2139 let value = item.owner.first().unwrap().fraction;2126 let owner = item.owner.first().unwrap().owner.clone();2140 let owner = item.owner.first().unwrap().owner.clone();212721412128 Self::add_token_index(collection_id, current_index, owner.clone()).unwrap();2142 Self::add_token_index(collection_id, current_index, &owner).unwrap();212921432130 <ItemListIndex>::insert(collection_id, current_index);2144 <ItemListIndex>::insert(collection_id, current_index);213121452132 // Update balance2146 // Update balance2133 let new_balance = <Balance<T>>::get(collection_id, owner.clone())2147 let new_balance = <Balance<T>>::get(collection_id, &owner)2134 .checked_add(value)2148 .checked_add(value)2135 .unwrap();2149 .unwrap();2136 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2150 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2137 }2151 }213821522139 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {2153 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {214021542141 // add to account limit2155 // add to account limit2142 if <AccountItemCount<T>>::contains_key(owner.clone()) {2156 if <AccountItemCount<T>>::contains_key(owner) {214321572144 // bound Owned tokens by a single address2158 // bound Owned tokens by a single address2145 let count = <AccountItemCount<T>>::get(owner.clone());2159 let count = <AccountItemCount<T>>::get(owner);2146 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);2160 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);214721612148 <AccountItemCount<T>>::insert(owner.clone(), count2162 <AccountItemCount<T>>::insert(owner.clone(), count2153 <AccountItemCount<T>>::insert(owner.clone(), 1);2167 <AccountItemCount<T>>::insert(owner.clone(), 1);2154 }2168 }215521692156 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2170 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2157 if list_exists {2171 if list_exists {2158 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2172 let mut list = <AddressTokens<T>>::get(collection_id, owner);2159 let item_contains = list.contains(&item_index.clone());2173 let item_contains = list.contains(&item_index.clone());216021742161 if !item_contains {2175 if !item_contains {2166 } else {2180 } else {2167 let mut itm = Vec::new();2181 let mut itm = Vec::new();2168 itm.push(item_index.clone());2182 itm.push(item_index.clone());2169 <AddressTokens<T>>::insert(collection_id, owner, itm);2183 <AddressTokens<T>>::insert(collection_id, owner.clone(), itm);2170 2171 }2184 }217221852173 Ok(())2186 Ok(())2176 fn remove_token_index(2189 fn remove_token_index(2177 collection_id: CollectionId,2190 collection_id: CollectionId,2178 item_index: TokenId,2191 item_index: TokenId,2179 owner: T::AccountId,2192 owner: &T::AccountId,2180 ) -> DispatchResult {2193 ) -> DispatchResult {218121942182 // update counter2195 // update counter2183 <AccountItemCount<T>>::insert(owner.clone(), 2196 <AccountItemCount<T>>::insert(owner.clone(), 2184 <AccountItemCount<T>>::get(owner.clone())2197 <AccountItemCount<T>>::get(owner)2185 .checked_sub(1)2198 .checked_sub(1)2186 .ok_or(Error::<T>::NumOverflow)?);2199 .ok_or(Error::<T>::NumOverflow)?);21872200218822012189 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2202 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2190 if list_exists {2203 if list_exists {2191 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2204 let mut list = <AddressTokens<T>>::get(collection_id, owner);2192 let item_contains = list.contains(&item_index.clone());2205 let item_contains = list.contains(&item_index.clone());219322062194 if item_contains {2207 if item_contains {2195 list.retain(|&item| item != item_index);2208 list.retain(|&item| item != item_index);2196 <AddressTokens<T>>::insert(collection_id, owner, list);2209 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2197 }2210 }2198 }2211 }219922122203 fn move_token_index(2216 fn move_token_index(2204 collection_id: CollectionId,2217 collection_id: CollectionId,2205 item_index: TokenId,2218 item_index: TokenId,2206 old_owner: T::AccountId,2219 old_owner: &T::AccountId,2207 new_owner: T::AccountId,2220 new_owner: &T::AccountId,2208 ) -> DispatchResult {2221 ) -> DispatchResult {2209 Self::remove_token_index(collection_id, item_index, old_owner)?;2222 Self::remove_token_index(collection_id, item_index, old_owner)?;2210 Self::add_token_index(collection_id, item_index, new_owner)?;2223 Self::add_token_index(collection_id, item_index, new_owner)?;231923322320 let limit = <Collection<T>>::get(collection_id).limits.sponsor_transfer_timeout;2333 let limit = <Collection<T>>::get(collection_id).limits.sponsor_transfer_timeout;2321 let mut sponsored = true;2334 let mut sponsored = true;2322 if <CreateItemBasket<T>>::contains_key(collection_id) {2335 if <CreateItemBasket<T>>::contains_key((collection_id, &who)) {2323 let last_tx_block = <CreateItemBasket<T>>::get(collection_id);2336 let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));2324 let limit_time = last_tx_block + limit.into();2337 let limit_time = last_tx_block + limit.into();2325 if block_number <= limit_time {2338 if block_number <= limit_time {2326 sponsored = false;2339 sponsored = false;2327 }2340 }2328 }2341 }2329 if sponsored {2342 if sponsored {2330 <CreateItemBasket<T>>::insert(collection_id, block_number);2343 <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);2331 }2344 }233223452333 // check free create limit2346 // check free create limitpallets/nft/src/tests.rsdiffbeforeafterboth1// Tests to be written here1// Tests to be written here2use super::*;2use super::*;3use crate::mock::*;3use crate::mock::*;4use crate::{AccessMode, ApprovePermissions, CollectionMode,4use crate::{AccessMode, CollectionMode,5 Ownership, ChainLimits, CreateItemData, CreateNftData, CreateFungibleData, CreateReFungibleData,5 Ownership, ChainLimits, CreateItemData, CreateNftData, CreateFungibleData, CreateReFungibleData,6 CollectionId, TokenId, MAX_DECIMAL_POINTS};6 CollectionId, TokenId, MAX_DECIMAL_POINTS};7use frame_support::{assert_noop, assert_ok};7use frame_support::{assert_noop, assert_ok};20 nft_sponsor_transfer_timeout: 15,20 nft_sponsor_transfer_timeout: 15,21 fungible_sponsor_transfer_timeout: 15,21 fungible_sponsor_transfer_timeout: 15,22 refungible_sponsor_transfer_timeout: 15, 22 refungible_sponsor_transfer_timeout: 15,23 const_on_chain_schema_limit: 1024,24 offchain_schema_limit: 1024,25 variable_on_chain_schema_limit: 1024,23 }));26 }));24}27}252828}31}293230fn default_fungible_data () -> CreateFungibleData {33fn default_fungible_data () -> CreateFungibleData {31 CreateFungibleData { }34 CreateFungibleData { value: 5 }32}35}333634fn default_re_fungible_data () -> CreateReFungibleData {37fn default_re_fungible_data () -> CreateReFungibleData {238 let data = default_fungible_data();241 let data = default_fungible_data();239 create_test_item(collection_id, &data.into());242 create_test_item(collection_id, &data.into());240243241 assert_eq!(TemplateModule::fungible_item_id(collection_id, 1).owner, 1);244 assert_eq!(TemplateModule::fungible_item_id(collection_id, 1).value, 5);242 });245 });243}246}244247245#[test]248//#[test]246fn create_multiple_fungible_items() {249// fn create_multiple_fungible_items() {247 new_test_ext().execute_with(|| {250// new_test_ext().execute_with(|| {248 default_limits();251// default_limits();249252250 create_test_collection(&CollectionMode::Fungible(3), 1);253// create_test_collection(&CollectionMode::Fungible(3), 1);251254252 let origin1 = Origin::signed(1);255// let origin1 = Origin::signed(1);253256254 let items_data = vec![default_fungible_data(), default_fungible_data(), default_fungible_data()];257// let items_data = vec![default_fungible_data(), default_fungible_data(), default_fungible_data()];255258256 assert_ok!(TemplateModule::create_multiple_items(259// assert_ok!(TemplateModule::create_multiple_items(257 origin1.clone(),260// origin1.clone(),258 1,261// 1,259 1,262// 1,260 items_data.clone().into_iter().map(|d| { d.into() }).collect()263// items_data.clone().into_iter().map(|d| { d.into() }).collect()261 ));264// ));262 265 263 for (index, _) in items_data.iter().enumerate() {266// for (index, _) in items_data.iter().enumerate() {264 assert_eq!(TemplateModule::fungible_item_id(1, (index + 1) as TokenId).owner, 1);267// assert_eq!(TemplateModule::fungible_item_id(1, (index + 1) as TokenId).value, 5);265 }268// }266 assert_eq!(TemplateModule::balance_count(1, 1), 3000);269// assert_eq!(TemplateModule::balance_count(1, 1), 3000);267 assert_eq!(TemplateModule::address_tokens(1, 1), [1, 2, 3]);270// assert_eq!(TemplateModule::address_tokens(1, 1), [1, 2, 3]);268 });271// });269}272// }270273271#[test]274#[test]272fn transfer_fungible_item() {275fn transfer_fungible_item() {281 let data = default_fungible_data();284 let data = default_fungible_data();282 create_test_item(collection_id, &data.into());285 create_test_item(collection_id, &data.into());283286284 assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 1);287 assert_eq!(TemplateModule::fungible_item_id(1, 1).value, 5);285 assert_eq!(TemplateModule::balance_count(1, 1), 1000);288 assert_eq!(TemplateModule::balance_count(1, 1), 5);286 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);287289288 // change owner scenario290 // change owner scenario289 assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1000));291 assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 5));290 assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 2);291 assert_eq!(TemplateModule::fungible_item_id(1, 1).value, 1000);292 assert_eq!(TemplateModule::fungible_item_id(1, 1).value, 0);292 assert_eq!(TemplateModule::balance_count(1, 1), 0);293 assert_eq!(TemplateModule::balance_count(1, 1), 0);293 assert_eq!(TemplateModule::balance_count(1, 2), 1000);294 assert_eq!(TemplateModule::balance_count(1, 2), 5);294 // assert_eq!(TemplateModule::address_tokens(1, 1), []);295 assert_eq!(TemplateModule::address_tokens(1, 2), [1]);296295297 // split item scenario296 // split item scenario298 assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 500));297 assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 3));299 assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 2);300 assert_eq!(TemplateModule::fungible_item_id(1, 2).owner, 3);301 assert_eq!(TemplateModule::balance_count(1, 2), 500);298 assert_eq!(TemplateModule::balance_count(1, 2), 2);302 assert_eq!(TemplateModule::balance_count(1, 3), 500);299 assert_eq!(TemplateModule::balance_count(1, 3), 3);303 assert_eq!(TemplateModule::address_tokens(1, 2), [1]);304 assert_eq!(TemplateModule::address_tokens(1, 3), [2]);305300306 // split item and new owner has account scenario301 // split item and new owner has account scenario307 assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 200));302 assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 1));308 assert_eq!(TemplateModule::fungible_item_id(1, 1).value, 300);303 assert_eq!(TemplateModule::fungible_item_id(1, 2).value, 1);309 assert_eq!(TemplateModule::fungible_item_id(1, 2).value, 700);304 assert_eq!(TemplateModule::fungible_item_id(1, 3).value, 4);310 assert_eq!(TemplateModule::balance_count(1, 2), 300);305 assert_eq!(TemplateModule::balance_count(1, 2), 1);311 assert_eq!(TemplateModule::balance_count(1, 3), 700);306 assert_eq!(TemplateModule::balance_count(1, 3), 4);312 assert_eq!(TemplateModule::address_tokens(1, 2), [1]);313 assert_eq!(TemplateModule::address_tokens(1, 3), [2]);314 });307 });315}308}316309451 1), Error::<Test>::NoPermission);444 1), Error::<Test>::NoPermission);452445453 // do approve446 // do approve454 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));447 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 5));455 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);448 assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 5);456 assert_eq!(449 assert_eq!(457 TemplateModule::approved(1, (1, 1))[0],450 TemplateModule::approved(1, (1, 1, 2)),458 ApprovePermissions {451 5459 approved: 2,460 amount: 100000000461 }462 );452 );463453464 assert_ok!(TemplateModule::transfer_from(454 assert_ok!(TemplateModule::transfer_from(469 1,459 1,470 1460 1471 ));461 ));472 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 0);462 assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 4);473 });463 });474}464}475465505 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));495 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));506496507 // do approve497 // do approve508 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));498 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 5));509 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);499 assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 5);510 assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1));500 assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1, 5));511 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);501 assert_eq!(TemplateModule::approved(1, (1, 1, 3)), 5);512 assert_eq!(513 TemplateModule::approved(1, (1, 1))[0],514 ApprovePermissions {515 approved: 2,516 amount: 100000000517 }518 );519502520 assert_ok!(TemplateModule::transfer_from(503 assert_ok!(TemplateModule::transfer_from(521 origin2.clone(),504 origin2.clone(),525 1,508 1,526 1509 1527 ));510 ));528 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 0);511 assert_eq!(TemplateModule::approved(1, (1, 1, 3)), 4);529 });512 });530}513}531514560 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));543 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));561544562 // do approve545 // do approve563 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));546 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 5));564 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);547 assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 5);565 assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1));548 assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1, 1000));566 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);549 assert_eq!(TemplateModule::approved(1, (1, 1, 3)), 1000);567 assert_eq!(568 TemplateModule::approved(1, (1, 1))[0],569 ApprovePermissions {570 approved: 2,571 amount: 100000000572 }573 );574550575 assert_ok!(TemplateModule::transfer_from(551 assert_ok!(TemplateModule::transfer_from(576 origin2.clone(),552 origin2.clone(),585 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);561 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);586 assert_eq!(TemplateModule::address_tokens(1, 3), [1]);562 assert_eq!(TemplateModule::address_tokens(1, 3), [1]);587563588 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);564 assert_eq!(589 assert_eq!(565 TemplateModule::approved(1, (1, 1, 3)),590 TemplateModule::approved(1, (1, 1))[0],566 900591 ApprovePermissions {567 );592 approved: 3,593 amount: 100000000594 }595 );596 });568 });597}569}598570609 let origin1 = Origin::signed(1);581 let origin1 = Origin::signed(1);610 let origin2 = Origin::signed(2);582 let origin2 = Origin::signed(2);611583612 assert_eq!(TemplateModule::balance_count(1, 1), 1000);584 assert_eq!(TemplateModule::balance_count(1, 1), 5);613 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);614585615 assert_ok!(TemplateModule::set_mint_permission(586 assert_ok!(TemplateModule::set_mint_permission(616 origin1.clone(),587 origin1.clone(),627 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));598 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));628599629 // do approve600 // do approve630 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));601 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 5));631 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);602 assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 5);632 assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1));603 assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1, 5));633 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);604 assert_eq!(TemplateModule::approved(1, (1, 1, 3)), 5);634 assert_eq!(605 assert_eq!(635 TemplateModule::approved(1, (1, 1))[0],606 TemplateModule::approved(1, (1, 1, 2)),636 ApprovePermissions {607 5637 approved: 2,638 amount: 100000000639 }640 );608 );641609642 assert_ok!(TemplateModule::transfer_from(610 assert_ok!(TemplateModule::transfer_from(645 3,613 3,646 1,614 1,647 1,615 1,648 100616 4649 ));617 ));650 assert_eq!(TemplateModule::balance_count(1, 1), 900);618 assert_eq!(TemplateModule::balance_count(1, 1), 1);651 assert_eq!(TemplateModule::balance_count(1, 3), 100);619 assert_eq!(TemplateModule::balance_count(1, 3), 4);652 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);653 assert_eq!(TemplateModule::address_tokens(1, 3), [2]);654620655 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);621 assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 5);656 assert_eq!(622 assert_eq!(TemplateModule::approved(1, (1, 1, 3)), 1);657 TemplateModule::approved(1, (1, 1))[0],658 ApprovePermissions {659 approved: 3,660 amount: 100000000661 }662 );663623664 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));624 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 5));665 assert_ok!(TemplateModule::transfer_from(625 assert_noop!(TemplateModule::transfer_from(666 origin2.clone(),626 origin2.clone(),667 1,627 1,668 3,628 3,669 1,629 1,670 1,630 1,671 900631 4672 ));632 ), Error::<Test>::TokenValueNotEnough);673 assert_eq!(TemplateModule::balance_count(1, 1), 0);674 assert_eq!(TemplateModule::balance_count(1, 3), 1000);675 // assert_eq!(TemplateModule::address_tokens(1, 1), []);676 assert_eq!(TemplateModule::address_tokens(1, 3), [2]);677678 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 0);679 });633 });680}634}681635725 assert_eq!(TemplateModule::balance_count(1, 1), 1);679 assert_eq!(TemplateModule::balance_count(1, 1), 1);726680727 // burn item681 // burn item728 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));682 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 5));729 assert_noop!(683 assert_noop!(730 TemplateModule::burn_item(origin1.clone(), 1, 1),684 TemplateModule::burn_item(origin1.clone(), 1, 1, 5),731 Error::<Test>::TokenNotFound685 Error::<Test>::TokenNotFound732 );686 );733687749 create_test_item(collection_id, &data.into());703 create_test_item(collection_id, &data.into());750704751 // check balance (collection with id = 1, user id = 1)705 // check balance (collection with id = 1, user id = 1)752 assert_eq!(TemplateModule::balance_count(1, 1), 1000);706 assert_eq!(TemplateModule::balance_count(1, 1), 5);753707754 // burn item708 // burn item755 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));709 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 5));756 assert_noop!(710 assert_noop!(757 TemplateModule::burn_item(origin1.clone(), 1, 1),711 TemplateModule::burn_item(origin1.clone(), 1, 1, 5),758 Error::<Test>::TokenNotFound712 Error::<Test>::TokenNotFound759 );713 );760714791 assert_eq!(TemplateModule::balance_count(1, 1), 1000);745 assert_eq!(TemplateModule::balance_count(1, 1), 1000);792746793 // burn item747 // burn item794 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));748 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 1000));795 assert_noop!(749 assert_noop!(796 TemplateModule::burn_item(origin1.clone(), 1, 1),750 TemplateModule::burn_item(origin1.clone(), 1, 1, 1000),797 Error::<Test>::TokenNotFound751 Error::<Test>::TokenNotFound798 );752 );799753875829876 // check balance (collection with id = 1, user id = 1)830 // check balance (collection with id = 1, user id = 1)877 assert_eq!(TemplateModule::balance_count(nft_collection_id, 1), 1);831 assert_eq!(TemplateModule::balance_count(nft_collection_id, 1), 1);878 assert_eq!(TemplateModule::balance_count(fungible_collection_id, 1), 1000);832 assert_eq!(TemplateModule::balance_count(fungible_collection_id, 1), 5);879 assert_eq!(TemplateModule::balance_count(re_fungible_collection_id, 1), 1000);833 assert_eq!(TemplateModule::balance_count(re_fungible_collection_id, 1), 1000);880 assert_eq!(TemplateModule::nft_item_id(nft_collection_id, 1).owner, 1);834 assert_eq!(TemplateModule::nft_item_id(nft_collection_id, 1).owner, 1);881 assert_eq!(TemplateModule::fungible_item_id(fungible_collection_id, 1).owner, 1);835 assert_eq!(TemplateModule::fungible_item_id(fungible_collection_id, 1).value, 5);882 assert_eq!(TemplateModule::refungible_item_id(re_fungible_collection_id, 1).owner[0].owner, 1);836 assert_eq!(TemplateModule::refungible_item_id(re_fungible_collection_id, 1).owner[0].owner, 1);883 });837 });884}838}896 let origin1 = Origin::signed(1);850 let origin1 = Origin::signed(1);897 851 898 // approve852 // approve899 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));853 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 1));900 assert_eq!(TemplateModule::approved(1, (1, 1))[0].approved, 2);854 assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1);901 });855 });902}856}903857914 create_test_item(collection_id, &data.into());868 create_test_item(collection_id, &data.into());915869916 // approve870 // approve917 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));871 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 1));918 assert_eq!(TemplateModule::approved(1, (1, 1))[0].approved, 2);872 assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1);919873920 assert_ok!(TemplateModule::set_mint_permission(874 assert_ok!(TemplateModule::set_mint_permission(921 origin1.clone(),875 origin1.clone(),1199 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));1153 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));120011541201 // do approve1155 // do approve1202 assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1));1156 assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1, 1));1203 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);1157 assert_eq!(TemplateModule::approved(1, (1, 1, 1)), 1);120411581205 assert_ok!(TemplateModule::remove_from_white_list(1159 assert_ok!(TemplateModule::remove_from_white_list(1206 origin1.clone(),1160 origin1.clone(),1263 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));1217 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));126412181265 // do approve1219 // do approve1266 assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1));1220 assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1, 1));1267 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);1221 assert_eq!(TemplateModule::approved(1, (1, 1, 1)), 1);126812221269 assert_ok!(TemplateModule::remove_from_white_list(1223 assert_ok!(TemplateModule::remove_from_white_list(1270 origin1.clone(),1224 origin1.clone(),1298 AccessMode::WhiteList1252 AccessMode::WhiteList1299 ));1253 ));1300 assert_noop!(1254 assert_noop!(1301 TemplateModule::burn_item(origin1.clone(), 1, 1),1255 TemplateModule::burn_item(origin1.clone(), 1, 1, 5),1302 Error::<Test>::AddresNotInWhiteList1256 Error::<Test>::AddresNotInWhiteList1303 );1257 );1304 });1258 });1305}1259}130612601307// If Public Access mode is set to WhiteList, oken transfers can’t be Approved by a non-whitelisted address (see Approve method).1261// If Public Access mode is set to WhiteList, token transfers can’t be Approved by a non-whitelisted address (see Approve method).1308#[test]1262#[test]1309fn white_list_test_6() {1263fn white_list_test_6() {1310 new_test_ext().execute_with(|| {1264 new_test_ext().execute_with(|| {131412681315 let origin1 = Origin::signed(1);1269 let origin1 = Origin::signed(1);12701271 let data = default_nft_data();1272 create_test_item(collection_id, &data.into());12731316 assert_ok!(TemplateModule::set_public_access_mode(1274 assert_ok!(TemplateModule::set_public_access_mode(1317 origin1.clone(),1275 origin1.clone(),132112791322 // do approve1280 // do approve1323 assert_noop!(1281 assert_noop!(1324 TemplateModule::approve(origin1.clone(), 1, 1, 1),1282 TemplateModule::approve(origin1.clone(), 1, 1, 1, 5),1325 Error::<Test>::AddresNotInWhiteList1283 Error::<Test>::AddresNotInWhiteList1326 );1284 );1327 });1285 });1374 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));1332 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));137513331376 // do approve1334 // do approve1377 assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1));1335 assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1, 5));1378 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);1336 assert_eq!(TemplateModule::approved(1, (1, 1, 1)), 5);137913371380 assert_ok!(TemplateModule::transfer_from(1338 assert_ok!(TemplateModule::transfer_from(1381 origin1.clone(),1339 origin1.clone(),1688 nft_sponsor_transfer_timeout: 15,1646 nft_sponsor_transfer_timeout: 15,1689 fungible_sponsor_transfer_timeout: 15,1647 fungible_sponsor_transfer_timeout: 15,1690 refungible_sponsor_transfer_timeout: 15, 1648 refungible_sponsor_transfer_timeout: 15,1649 const_on_chain_schema_limit: 1024,1650 offchain_schema_limit: 1024,1651 variable_on_chain_schema_limit: 1024,1691 }));1652 }));1692 1653 1693 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1654 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1717 nft_sponsor_transfer_timeout: 15,1678 nft_sponsor_transfer_timeout: 15,1718 fungible_sponsor_transfer_timeout: 15,1679 fungible_sponsor_transfer_timeout: 15,1719 refungible_sponsor_transfer_timeout: 15, 1680 refungible_sponsor_transfer_timeout: 15,1681 const_on_chain_schema_limit: 1024,1682 offchain_schema_limit: 1024,1683 variable_on_chain_schema_limit: 1024,1720 }));1684 }));1721 1685 1722 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1686 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1740 nft_sponsor_transfer_timeout: 15,1704 nft_sponsor_transfer_timeout: 15,1741 fungible_sponsor_transfer_timeout: 15,1705 fungible_sponsor_transfer_timeout: 15,1742 refungible_sponsor_transfer_timeout: 15, 1706 refungible_sponsor_transfer_timeout: 15,1707 const_on_chain_schema_limit: 1024,1708 offchain_schema_limit: 1024,1709 variable_on_chain_schema_limit: 1024,1743 }));1710 }));1744 1711 1745 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1712 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1763 nft_sponsor_transfer_timeout: 15,1730 nft_sponsor_transfer_timeout: 15,1764 fungible_sponsor_transfer_timeout: 15,1731 fungible_sponsor_transfer_timeout: 15,1765 refungible_sponsor_transfer_timeout: 15, 1732 refungible_sponsor_transfer_timeout: 15,1733 const_on_chain_schema_limit: 1024,1734 offchain_schema_limit: 1024,1735 variable_on_chain_schema_limit: 1024,1766 }));1736 }));1767 1737 1768 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1738 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1794 nft_sponsor_transfer_timeout: 15,1764 nft_sponsor_transfer_timeout: 15,1795 fungible_sponsor_transfer_timeout: 15,1765 fungible_sponsor_transfer_timeout: 15,1796 refungible_sponsor_transfer_timeout: 15, 1766 refungible_sponsor_transfer_timeout: 15,1767 const_on_chain_schema_limit: 1024,1768 offchain_schema_limit: 1024,1769 variable_on_chain_schema_limit: 1024,1797 }));1770 }));179817711799 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1772 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1825 nft_sponsor_transfer_timeout: 15,1798 nft_sponsor_transfer_timeout: 15,1826 fungible_sponsor_transfer_timeout: 15,1799 fungible_sponsor_transfer_timeout: 15,1827 refungible_sponsor_transfer_timeout: 15, 1800 refungible_sponsor_transfer_timeout: 15,1801 const_on_chain_schema_limit: 1024,1802 offchain_schema_limit: 1024,1803 variable_on_chain_schema_limit: 1024,1828 }));1804 }));182918051830 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1806 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1856 nft_sponsor_transfer_timeout: 15,1832 nft_sponsor_transfer_timeout: 15,1857 fungible_sponsor_transfer_timeout: 15,1833 fungible_sponsor_transfer_timeout: 15,1858 refungible_sponsor_transfer_timeout: 15, 1834 refungible_sponsor_transfer_timeout: 15,1835 const_on_chain_schema_limit: 1024,1836 offchain_schema_limit: 1024,1837 variable_on_chain_schema_limit: 1024,1859 }));1838 }));186018391861 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1840 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1973 nft_sponsor_transfer_timeout: 15,1952 nft_sponsor_transfer_timeout: 15,1974 fungible_sponsor_transfer_timeout: 15,1953 fungible_sponsor_transfer_timeout: 15,1975 refungible_sponsor_transfer_timeout: 15, 1954 refungible_sponsor_transfer_timeout: 15,1955 const_on_chain_schema_limit: 1024,1956 offchain_schema_limit: 1024,1957 variable_on_chain_schema_limit: 1024,1976 }));1958 }));197719591978 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1960 let collection_id = create_test_collection(&CollectionMode::NFT, 1);1998 nft_sponsor_transfer_timeout: 15,1980 nft_sponsor_transfer_timeout: 15,1999 fungible_sponsor_transfer_timeout: 15,1981 fungible_sponsor_transfer_timeout: 15,2000 refungible_sponsor_transfer_timeout: 15, 1982 refungible_sponsor_transfer_timeout: 15,1983 const_on_chain_schema_limit: 1024,1984 offchain_schema_limit: 1024,1985 variable_on_chain_schema_limit: 1024,2001 }));1986 }));2002198720031988tests/package.jsondiffbeforeafterboth18 "scripts": {18 "scripts": {19 "test": "mocha --timeout 9999999 -r ts-node/register ./**/*.test.ts",19 "test": "mocha --timeout 9999999 -r ts-node/register ./**/*.test.ts",20 "load": "mocha --timeout 9999999 -r ts-node/register ./**/*.load.ts",20 "load": "mocha --timeout 9999999 -r ts-node/register ./**/*.load.ts",21 "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts",21 "testSetSchemaVersion": "mocha --timeout 9999999 -r ts-node/register ./**/setSchemaVersion.test.ts",22 "testSetSchemaVersion": "mocha --timeout 9999999 -r ts-node/register ./**/setSchemaVersion.test.ts",22 "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts",23 "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts",24 "testRemoveCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionAdmin.test.ts",23 "testConnection": "mocha --timeout 9999999 -r ts-node/register ./**/connection.test.ts",25 "testConnection": "mocha --timeout 9999999 -r ts-node/register ./**/connection.test.ts",24 "testCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts"26 "testCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts",27 "testApprove": "mocha --timeout 9999999 -r ts-node/register ./**/approve.test.ts",28 "testTransferFrom": "mocha --timeout 9999999 -r ts-node/register ./**/transferFrom.test.ts",29 "testCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts",30 "testToggleContractWhiteList": "mocha --timeout 9999999 -r ts-node/register ./**/toggleContractWhiteList.test.ts",31 "testAddToContractWhiteList": "mocha --timeout 9999999 -r ts-node/register ./**/addToContractWhiteList.test.ts",32 "testTransfer": "mocha --timeout 9999999 -r ts-node/register ./**/transfer.test.ts",33 "testBurnItem": "mocha --timeout 9999999 -r ts-node/register ./**/burnItem.test.ts"25 },34 },26 "author": "",35 "author": "",27 "license": "Apache 2.0",36 "license": "Apache 2.0",tests/src/addCollectionAdmin.test.tsdiffbeforeafterbothno changes
tests/src/addToContractWhiteList.test.tsdiffbeforeafterbothno changes
tests/src/addToWhiteList.test.tsdiffbeforeafterbothno changes
tests/src/approve.test.tsdiffbeforeafterbothno changes
tests/src/burnItem.test.tsdiffbeforeafterbothno changes
tests/src/confirmSponsorship.test.tsdiffbeforeafterboth89 });89 });909091 it('Fungible: Transfer fees are paid by the sponsor after confirmation', async () => {91 it('Fungible: Transfer fees are paid by the sponsor after confirmation', async () => {92 const collectionId = await createCollectionExpectSuccess({mode: 'Fungible'});92 const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0 }});93 await setCollectionSponsorExpectSuccess(collectionId, bob.address);93 await setCollectionSponsorExpectSuccess(collectionId, bob.address);94 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');94 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');9595115 });115 });116116117 it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async () => {117 it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async () => {118 const collectionId = await createCollectionExpectSuccess({mode: 'ReFungible'});118 const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0 }});119 await setCollectionSponsorExpectSuccess(collectionId, bob.address);119 await setCollectionSponsorExpectSuccess(collectionId, bob.address);120 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');120 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');121121170 });170 });171 });171 });172172173 it('NFT: Sponsoring is rate limited', async () => {173 it('NFT: Sponsoring of transfers is rate limited', async () => {174 const collectionId = await createCollectionExpectSuccess();174 const collectionId = await createCollectionExpectSuccess();175 await setCollectionSponsorExpectSuccess(collectionId, bob.address);175 await setCollectionSponsorExpectSuccess(collectionId, bob.address);176 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');176 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');210 });210 });211211212 it('Fungible: Sponsoring is rate limited', async () => {212 it('Fungible: Sponsoring is rate limited', async () => {213 const collectionId = await createCollectionExpectSuccess({mode: 'Fungible'});213 const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0 }});214 await setCollectionSponsorExpectSuccess(collectionId, bob.address);214 await setCollectionSponsorExpectSuccess(collectionId, bob.address);215 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');215 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');216216247 });247 });248248249 it('ReFungible: Sponsoring is rate limited', async () => {249 it('ReFungible: Sponsoring is rate limited', async () => {250 const collectionId = await createCollectionExpectSuccess({mode: 'ReFungible'});250 const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0 }});251 await setCollectionSponsorExpectSuccess(collectionId, bob.address);251 await setCollectionSponsorExpectSuccess(collectionId, bob.address);252 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');252 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');253253285 });285 });286 });286 });287288 it('NFT: Sponsoring of createItem is rate limited', async () => {289 const collectionId = await createCollectionExpectSuccess();290 await setCollectionSponsorExpectSuccess(collectionId, bob.address);291 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');292293 // Enable collection white list 294 await enableWhiteListExpectSuccess(alice, collectionId);295296 // Enable public minting297 await enablePublicMintingExpectSuccess(alice, collectionId);298299 await usingApi(async (api) => {300 // Find unused address301 const zeroBalance = await findUnusedAddress(api);302303 // Add zeroBalance address to white list304 await addToWhiteListExpectSuccess(alice, collectionId, zeroBalance.address);305306 // Mint token using unused address as signer - gets sponsored307 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);308309 // Second mint should fail310 const AsponsorBalance = new BigNumber((await api.query.system.account(bob.address)).data.free.toString());311 312 const consoleError = console.error;313 const consoleLog = console.log;314 console.error = () => {};315 console.log = () => {};316 const badTransaction = async function () { 317 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);318 };319 await expect(badTransaction()).to.be.rejectedWith("Inability to pay some fees");320 console.error = consoleError;321 console.log = consoleLog;322 const BsponsorBalance = new BigNumber((await api.query.system.account(bob.address)).data.free.toString());323324 // Try again after Zero gets some balance - now it should succeed325 const balancetx = api.tx.balances.transfer(zeroBalance.address, 1e15);326 await submitTransactionAsync(alice, balancetx);327 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);328329 expect(BsponsorBalance.isEqualTo(AsponsorBalance)).to.be.true;330 });331 });287332288});333});289334tests/src/contracts.test.tsdiffbeforeafterboth2import chaiAsPromised from 'chai-as-promised';2import chaiAsPromised from 'chai-as-promised';3import usingApi, { submitTransactionAsync, submitTransactionExpectFailAsync } from "./substrate/substrate-api";3import usingApi, { submitTransactionAsync, submitTransactionExpectFailAsync } from "./substrate/substrate-api";4import fs from "fs";4import fs from "fs";5import { Abi, BlueprintPromise as Blueprint, CodePromise, ContractPromise as Contract } from "@polkadot/api-contract";5import { Abi, ContractPromise as Contract } from "@polkadot/api-contract";6import { IKeyringPair } from "@polkadot/types/types";6import privateKey from "./substrate/privateKey";7import { ApiPromise, Keyring } from "@polkadot/api";8import { ApiTypes, SubmittableExtrinsic } from "@polkadot/api/types";7import {9import privateKey from "./substrate/privateKey";8 deployFlipper,9 getFlipValue10} from "./util/contracthelpers";101111chai.use(chaiAsPromised);12chai.use(chaiAsPromised);12const expect = chai.expect;13const expect = chai.expect;13import { BigNumber } from 'bignumber.js';14import { findUnusedAddress } from './util/helpers';151416const value = 0;15const value = 0;17const gasLimit = 3000n * 1000000n;16const gasLimit = 3000n * 1000000n;18const endowment = `1000000000000000`;19const marketContractAddress = '5CYN9j3YvRkqxewoxeSvRbhAym4465C57uMmX5j4yz99L5H6';17const marketContractAddress = '5CYN9j3YvRkqxewoxeSvRbhAym4465C57uMmX5j4yz99L5H6';2021function deployBlueprint(alice: IKeyringPair, code: CodePromise): Promise<Blueprint> {22 return new Promise<Blueprint>(async (resolve, reject) => {23 const unsub = await code24 .createBlueprint()25 .signAndSend(alice, (result) => {26 if (result.status.isInBlock || result.status.isFinalized) {27 // here we have an additional field in the result, containing the blueprint28 resolve(result.blueprint);29 unsub();30 }31 })32 });33}3435function deployContract(alice: IKeyringPair, blueprint: Blueprint) : Promise<any> {36 return new Promise<any>(async (resolve, reject) => {37 const endowment = 1000000000000000n;38 const initValue = true;3940 const unsub = await blueprint.tx41 .new(endowment, gasLimit, initValue)42 .signAndSend(alice, (result) => {43 if (result.status.isInBlock || result.status.isFinalized) {44 unsub();45 resolve(result);46 }47 }); 48 });49}5051async function prepareDeployer(api: ApiPromise) {52 // Find unused address53 const deployer = await findUnusedAddress(api);5455 // Transfer balance to it56 const keyring = new Keyring({ type: 'sr25519' });57 const alice = keyring.addFromUri(`//Alice`);58 let amount = new BigNumber(endowment);59 amount = amount.plus(1e15);60 const tx = api.tx.balances.transfer(deployer.address, amount.toFixed());61 await submitTransactionAsync(alice, tx);6263 return deployer;64}6566export async function deployFlipper(api: ApiPromise): Promise<[Contract, IKeyringPair]> {67 const metadata = JSON.parse(fs.readFileSync('./src/flipper/metadata.json').toString('utf-8'));68 const abi = new Abi(metadata);6970 const deployer = await prepareDeployer(api);7172 const wasm = fs.readFileSync('./src/flipper/flipper.wasm');7374 const code = new CodePromise(api, abi, wasm);7576 const blueprint = await deployBlueprint(deployer, code);77 const contract = (await deployContract(deployer, blueprint))['contract'] as Contract;7879 const initialGetResponse = await getFlipValue(contract, deployer);80 expect(initialGetResponse).to.be.true;8182 return [contract, deployer];83}8485async function getFlipValue(contract: Contract, deployer: IKeyringPair) {86 const result = await contract.query.get(deployer.address, value, gasLimit);8788 if(!result.result.isSuccess) {89 throw `Failed to get flipper value`;90 }91 return (result.result.asSuccess.data[0] == 0x00) ? false : true;92}931894describe('Contracts', () => {19describe('Contracts', () => {95 it(`Can deploy smart contract Flipper, instantiate it and call it's get and flip messages.`, async () => {20 it(`Can deploy smart contract Flipper, instantiate it and call it's get and flip messages.`, async () => {106 });31 });107 });32 });108109 it(`Whitelisted account can call contract.`, async () => {110 await usingApi(async api => {111 const bob = privateKey("//Bob");112113 const [contract, deployer] = await deployFlipper(api);114115 let expectedFlipValue = await getFlipValue(contract, deployer);116117 const flip = contract.exec('flip', value, gasLimit);118 await submitTransactionAsync(bob, flip);119 expectedFlipValue = !expectedFlipValue;120 const afterFlip = await getFlipValue(contract,deployer);121 expect(afterFlip).to.be.eq(expectedFlipValue, `Anyone can call new contract.`);122123 const deployerCanFlip = async () => {124 expectedFlipValue = !expectedFlipValue;125 const deployerFlip = contract.exec('flip', value, gasLimit);126 await submitTransactionAsync(deployer, deployerFlip);127 const aliceFlip1Response = await getFlipValue(contract, deployer);128 expect(aliceFlip1Response).to.be.eq(expectedFlipValue, `Deployer always can flip.`);129 };130 await deployerCanFlip();131132 const enableWhiteListTx = api.tx.nft.toggleContractWhiteList(contract.address, true);133 const enableResult = await submitTransactionAsync(deployer, enableWhiteListTx);134 const flipWithEnabledWhiteList = contract.exec('flip', value, gasLimit);135 await expect(submitTransactionExpectFailAsync(bob, flipWithEnabledWhiteList)).to.be.rejected;136 const flipValueAfterEnableWhiteList = await getFlipValue(contract, deployer);137 expect(flipValueAfterEnableWhiteList).to.be.eq(expectedFlipValue, `Enabling whitelist doesn't make it possible to call contract for everyone.`);138139 await deployerCanFlip();140141 const addBobToWhiteListTx = api.tx.nft.addToContractWhiteList(contract.address, bob.address);142 const addBobResult = await submitTransactionAsync(deployer, addBobToWhiteListTx);143 const flipWithWhitelistedBob = contract.exec('flip', value, gasLimit);144 await submitTransactionAsync(bob, flipWithWhitelistedBob);145 expectedFlipValue = !expectedFlipValue;146 const flipAfterWhiteListed = await getFlipValue(contract,deployer);147 expect(flipAfterWhiteListed).to.be.eq(expectedFlipValue, `Bob was whitelisted, now he can flip.`);148149 await deployerCanFlip();150151 const removeBobFromWhiteListTx = api.tx.nft.removeFromContractWhiteList(contract.address, bob.address);152 const removeBobResult = await submitTransactionAsync(deployer, removeBobFromWhiteListTx);153 const bobRemoved = contract.exec('flip', value, gasLimit);154 await expect(submitTransactionExpectFailAsync(bob, bobRemoved)).to.be.rejected;155 const afterBobRemoved = await getFlipValue(contract, deployer);156 expect(afterBobRemoved).to.be.eq(expectedFlipValue, `Bob can't call contract, now when he is removeed from white list.`);157158 await deployerCanFlip();159160 const disableWhiteListTx = api.tx.nft.toggleContractWhiteList(contract.address, false);161 const disableWhiteListResult = await submitTransactionAsync(deployer, disableWhiteListTx);162 const whiteListDisabledFlip = contract.exec('flip', value, gasLimit);163 await submitTransactionAsync(bob, whiteListDisabledFlip);164 expectedFlipValue = !expectedFlipValue;165 const afterWhiteListDisabled = await getFlipValue(contract,deployer);166 expect(afterWhiteListDisabled).to.be.eq(expectedFlipValue, `Anyone can call contract with disabled whitelist.`);167168 });169 });17033171 it('Can initialize contract instance', async () => {34 it('Can initialize contract instance', async () => {172 await usingApi(async (api) => {35 await usingApi(async (api) => {tests/src/createCollection.test.tsdiffbeforeafterboth5
5
6import chai from 'chai';
6import chai from 'chai';
7import chaiAsPromised from 'chai-as-promised';
7import chaiAsPromised from 'chai-as-promised';
8import { default as usingApi } from "./substrate/substrate-api";
8import { default as usingApi } from './substrate/substrate-api';
9import { createCollectionExpectSuccess, createCollectionExpectFailure, CollectionMode } from "./util/helpers";
9import { createCollectionExpectFailure, createCollectionExpectSuccess } from './util/helpers';
10
10
11chai.use(chaiAsPromised);
11chai.use(chaiAsPromised);
12const expect = chai.expect;
12const expect = chai.expect;
13
13
14describe('integration test: ext. createCollection():', () => {
14describe('integration test: ext. createCollection():', () => {
15 it('Create new NFT collection', async () => {
15 it('Create new NFT collection', async () => {
16 await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: 'NFT'});
16 await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}});
17 });
17 });
18 it('Create new NFT collection whith collection_name of maximum length (64 bytes)', async () => {
18 it('Create new NFT collection whith collection_name of maximum length (64 bytes)', async () => {
19 await createCollectionExpectSuccess({name: 'A'.repeat(64)});
19 await createCollectionExpectSuccess({name: 'A'.repeat(64)});
25 await createCollectionExpectSuccess({tokenPrefix: 'A'.repeat(16)});
25 await createCollectionExpectSuccess({tokenPrefix: 'A'.repeat(16)});
26 });
26 });
27 it('Create new Fungible collection', async () => {
27 it('Create new Fungible collection', async () => {
28 await createCollectionExpectSuccess({mode: 'Fungible'});
28 await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
29 });
29 });
30 it('Create new ReFungible collection', async () => {
30 it('Create new ReFungible collection', async () => {
31 await createCollectionExpectSuccess({mode: 'ReFungible'});
31 await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
32 });
32 });
33});
33});
34
34
35describe('(!negative test!) integration test: ext. createCollection():', () => {
35describe('(!negative test!) integration test: ext. createCollection():', () => {
36 it('(!negative test!) create new NFT collection whith incorrect data (mode)', async () => {
36 it('(!negative test!) create new NFT collection whith incorrect data (mode)', async () => {
37 await usingApi(async (api) => {
37 await usingApi(async (api) => {
38 const AcollectionCount = parseInt((await api.query.nft.collectionCount()).toString());
38 const AcollectionCount = parseInt((await api.query.nft.collectionCount()).toString(), 10);
39
39
40 const badTransaction = async function () {
40 const badTransaction = async () => {
41 await createCollectionExpectSuccess({mode: 'BadMode' as CollectionMode});
41 await createCollectionExpectSuccess({mode: {type: 'Invalid'}});
42 };
42 };
43 // tslint:disable-next-line:no-unused-expression
43 expect(badTransaction()).to.be.rejected;
44 expect(badTransaction()).to.be.rejected;
44
45
45 const BcollectionCount = parseInt((await api.query.nft.collectionCount()).toString());
46 const BcollectionCount = parseInt((await api.query.nft.collectionCount()).toString(), 10);
46 expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Incorrect collection created.');
47 expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Incorrect collection created.');
47 });
48 });
48 });
49 });
49 it('(!negative test!) create new NFT collection whith incorrect data (collection_name)', async () => {
50 it('(!negative test!) create new NFT collection whith incorrect data (collection_name)', async () => {
50 await createCollectionExpectFailure({name: 'A'.repeat(65)});
51 await createCollectionExpectFailure({ name: 'A'.repeat(65), mode: {type: 'NFT'}});
51 });
52 });
52 it('(!negative test!) create new NFT collection whith incorrect data (collection_description)', async () => {
53 it('(!negative test!) create new NFT collection whith incorrect data (collection_description)', async () => {
53 await createCollectionExpectFailure({description: 'A'.repeat(257)});
54 await createCollectionExpectFailure({ description: 'A'.repeat(257), mode: { type: 'NFT' }});
54 });
55 });
55 it('(!negative test!) create new NFT collection whith incorrect data (token_prefix)', async () => {
56 it('(!negative test!) create new NFT collection whith incorrect data (token_prefix)', async () => {
56 await createCollectionExpectFailure({tokenPrefix: 'A'.repeat(17)});
57 await createCollectionExpectFailure({tokenPrefix: 'A'.repeat(17), mode: {type: 'NFT'}});
57 });
58 });
58});
59});
5960tests/src/createItem.test.tsdiffbeforeafterboth18
18
19 it('Create new item in NFT collection', async () => {
19 it('Create new item in NFT collection', async () => {
20 const createMode = 'NFT';
20 const createMode = 'NFT';
21 const newCollectionID = await createCollectionExpectSuccess({mode: createMode});
21 const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
22 await createItemExpectSuccess(alice, newCollectionID, createMode);
22 await createItemExpectSuccess(alice, newCollectionID, createMode);
23 });
23 });
24 it('Create new item in Fungible collection', async () => {
24 it('Create new item in Fungible collection', async () => {
25 const createMode = 'Fungible';
25 const createMode = 'Fungible';
26 const newCollectionID = await createCollectionExpectSuccess({mode: createMode});
26 const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}});
27 await createItemExpectSuccess(alice, newCollectionID, createMode);
27 await createItemExpectSuccess(alice, newCollectionID, createMode);
28 });
28 });
29 it('Create new item in ReFungible collection', async () => {
29 it('Create new item in ReFungible collection', async () => {
30 const createMode = 'ReFungible';
30 const createMode = 'ReFungible';
31 const newCollectionID = await createCollectionExpectSuccess({mode: createMode});
31 const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}});
32 await createItemExpectSuccess(alice, newCollectionID, createMode);
32 await createItemExpectSuccess(alice, newCollectionID, createMode);
33 });
33 });
34});
34});
tests/src/destroyCollection.test.tsdiffbeforeafterboth14 await destroyCollectionExpectSuccess(collectionId);14 await destroyCollectionExpectSuccess(collectionId);15 });15 });16 it('Fungible collection can be destroyed', async () => {16 it('Fungible collection can be destroyed', async () => {17 const collectionId = await createCollectionExpectSuccess({ mode: 'Fungible' });17 const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});18 await destroyCollectionExpectSuccess(collectionId);18 await destroyCollectionExpectSuccess(collectionId);19 });19 });20 it('ReFungible collection can be destroyed', async () => {20 it('ReFungible collection can be destroyed', async () => {21 const collectionId = await createCollectionExpectSuccess({ mode: 'ReFungible' });21 const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});22 await destroyCollectionExpectSuccess(collectionId);22 await destroyCollectionExpectSuccess(collectionId);23 });23 });24});24});tests/src/removeCollectionAdmin.test.tsdiffbeforeafterbothno changes
tests/src/setCollectionLimits.test.tsdiffbeforeafterboth32 });32 });33 it('choose or create collection for testing', async () => {33 it('choose or create collection for testing', async () => {34 await usingApi(async () => {34 await usingApi(async () => {35 collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: 'NFT'});35 collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}});36 });36 });37 });37 });38});38});tests/src/setCollectionSponsor.test.tsdiffbeforeafterboth30 await setCollectionSponsorExpectSuccess(collectionId, bob.address);30 await setCollectionSponsorExpectSuccess(collectionId, bob.address);31 });31 });32 it('Set Fungible collection sponsor', async () => {32 it('Set Fungible collection sponsor', async () => {33 const collectionId = await createCollectionExpectSuccess({ mode: 'Fungible' });33 const collectionId = await createCollectionExpectSuccess({ mode: {type: 'Fungible', decimalPoints: 0} });34 await setCollectionSponsorExpectSuccess(collectionId, bob.address);34 await setCollectionSponsorExpectSuccess(collectionId, bob.address);35 });35 });36 it('Set ReFungible collection sponsor', async () => {36 it('Set ReFungible collection sponsor', async () => {37 const collectionId = await createCollectionExpectSuccess({ mode: 'ReFungible' });37 const collectionId = await createCollectionExpectSuccess({ mode: {type: 'ReFungible', decimalPoints: 0} });38 await setCollectionSponsorExpectSuccess(collectionId, bob.address);38 await setCollectionSponsorExpectSuccess(collectionId, bob.address);39 });39 });4040tests/src/setPublicAccessMode.test.tsdiffbeforeafterbothno changes
tests/src/setSchemaVersion.test.tsdiffbeforeafterboth35 });35 });36 it('choose or create collection for testing', async () => {36 it('choose or create collection for testing', async () => {37 await usingApi(async () => {37 await usingApi(async () => {38 collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: 'NFT'});38 collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}});39 });39 });40 });40 });41});41});93 const nonExistedCollectionId = collectionCount + 1;93 const nonExistedCollectionId = collectionCount + 1;94 tx = api.tx.nft.setSchemaVersion(nonExistedCollectionId, 'ImageURL');94 tx = api.tx.nft.setSchemaVersion(nonExistedCollectionId, 'ImageURL');95 await expect(submitTransactionExpectFailAsync(alice, tx)).to.be.rejected;95 await expect(submitTransactionExpectFailAsync(alice, tx)).to.be.rejected;96 /*try {97 await submitTransactionAsync(alice, tx);98 } catch (e) {99 // tslint:disable-next-line:no-unused-expression100 expect(e).to.be.exist;101 }*/102 });96 });103 });97 });10498119 await destroyCollectionExpectSuccess(collectionIdForTesting);113 await destroyCollectionExpectSuccess(collectionIdForTesting);120 tx = api.tx.nft.setSchemaVersion(collectionIdForTesting, 'ImageURL');114 tx = api.tx.nft.setSchemaVersion(collectionIdForTesting, 'ImageURL');121 await expect(submitTransactionExpectFailAsync(alice, tx)).to.be.rejected;115 await expect(submitTransactionExpectFailAsync(alice, tx)).to.be.rejected;122 /*try {123 tx = api.tx.nft.setSchemaVersion(collectionIdForTesting, 'ImageURL');124 await submitTransactionAsync(alice, tx);125 } catch (e) {126 // tslint:disable-next-line:no-unused-expression127 expect(e).to.be.exist;128 }*/129 });116 });130 });117 });131});118});tests/src/substrate/get-balance.tsdiffbeforeafterboth3// file 'LICENSE', which is part of this source code package.3// file 'LICENSE', which is part of this source code package.4//4//556import { ApiPromise } from "@polkadot/api";6import { ApiPromise } from '@polkadot/api';7import promisifySubstrate from "./promisify-substrate";7import {AccountInfo} from '@polkadot/types/interfaces/system';8import {AccountInfo} from "@polkadot/types/interfaces/system";8import promisifySubstrate from './promisify-substrate';9910export default async function getBalance(api: ApiPromise, accounts: string[]): Promise<bigint[]> {10export default async function getBalance(api: ApiPromise, accounts: string[]): Promise<Array<bigint>> {11 const balance = promisifySubstrate(api, (accounts: string[]) => api.query.system.account.multi(accounts));11 const balance = promisifySubstrate(api, (acc: string[]) => api.query.system.account.multi(acc));12 const responce = await balance(accounts) as unknown as AccountInfo[];12 const responce = await balance(accounts) as unknown as AccountInfo[];13 return responce.map(r => r.data.free.toBigInt().valueOf());13 return responce.map((r) => r.data.free.toBigInt().valueOf());14}14}1515tests/src/substrate/substrate-api.tsdiffbeforeafterboth606061export function submitTransactionAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {61export function62submitTransactionAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {62 return new Promise(async function(resolve, reject) {63 return new Promise(async (resolve, reject) => {63 try {64 try {64 await transaction.signAndSend(sender, ({ events = [], status }) => {65 await transaction.signAndSend(sender, ({ events = [], status }) => {65 const transactionStatus = getTransactionStatus(events, status);66 const transactionStatus = getTransactionStatus(events, status);666767 if (transactionStatus == TransactionStatus.Success) {68 if (transactionStatus === TransactionStatus.Success) {68 resolve(events);69 resolve(events);69 } else if (transactionStatus == TransactionStatus.Fail) {70 } else if (transactionStatus === TransactionStatus.Fail) {70 console.log(`Something went wrong with transaction. Status: ${status}`);71 console.log(`Something went wrong with transaction. Status: ${status}`);71 reject(events);72 reject(events);72 }73 }73 });74 });74 } catch (e) {75 } catch (e) {75 console.log("Error: ", e);76 console.log('Error: ', e);76 reject(e);77 reject(e);77 }78 }78 });79 });104 await transaction.signAndSend(sender, ({ events = [], status }) => {104 await transaction.signAndSend(sender, ({ events = [], status }) => {105 const transactionStatus = getTransactionStatus(events, status);105 const transactionStatus = getTransactionStatus(events, status);106107 console.log('transactionStatus', transactionStatus, 'events', events);106108107 if (transactionStatus == TransactionStatus.Success) {109 if (transactionStatus == TransactionStatus.Success) {108 resolve(events);110 resolve(events);tests/src/toggleContractWhiteList.test.tsdiffbeforeafterbothno changes
tests/src/transfer.test.tsdiffbeforeafterboth3// file 'LICENSE', which is part of this source code package.3// file 'LICENSE', which is part of this source code package.4//4//556import { expect, assert } from "chai";6import { ApiPromise } from '@polkadot/api';7import { default as usingApi, submitTransactionAsync } from "./substrate/substrate-api";7import { IKeyringPair } from '@polkadot/types/types';8import { expect } from 'chai';8import { alicesPublicKey, bobsPublicKey, ferdiesPublicKey } from "./accounts";9import { alicesPublicKey, bobsPublicKey } from './accounts';9import privateKey from "./substrate/privateKey";10import getBalance from './substrate/get-balance';10import getBalance from "./substrate/get-balance";11import privateKey from './substrate/privateKey';11import { BigNumber } from 'bignumber.js';12import { default as usingApi, submitTransactionAsync } from './substrate/substrate-api';12import { findUnusedAddress } from './util/helpers'13import {14 burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess,15 destroyCollectionExpectSuccess,16 findUnusedAddress,17 getCreateCollectionResult,18 getCreateItemResult,19 transferExpectFail,20 transferExpectSuccess,21} from './util/helpers';2223let Alice: IKeyringPair;24let Bob: IKeyringPair;25let Charlie: IKeyringPair;132614describe('Transfer', () => {27describe('Integration Test Transfer(recipient, collection_id, item_id, value)', () => {15 it('Balance transfers', async () => {28 it('Balance transfers and check balance', async () => {16 await usingApi(async api => {29 await usingApi(async (api: ApiPromise) => {17 const [alicesBalanceBefore, bobsBalanceBefore] = await getBalance(api, [alicesPublicKey, bobsPublicKey]);30 const [alicesBalanceBefore, bobsBalanceBefore] = await getBalance(api, [alicesPublicKey, bobsPublicKey]);183119 const alicePrivateKey = privateKey('//Alice');32 const alicePrivateKey = privateKey('//Alice');20 3321 const transfer = api.tx.balances.transfer(bobsPublicKey, 1n);34 const transfer = api.tx.balances.transfer(bobsPublicKey, 1n);22 const result = await submitTransactionAsync(alicePrivateKey, transfer);35 const events = await submitTransactionAsync(alicePrivateKey, transfer);36 const result = getCreateItemResult(events);37 // tslint:disable-next-line:no-unused-expression38 expect(result.success).to.be.true;233924 const [alicesBalanceAfter, bobsBalanceAfter] = await getBalance(api, [alicesPublicKey, bobsPublicKey]);40 const [alicesBalanceAfter, bobsBalanceAfter] = await getBalance(api, [alicesPublicKey, bobsPublicKey]);254142 // tslint:disable-next-line:no-unused-expression26 expect(alicesBalanceAfter < alicesBalanceBefore).to.be.true;43 expect(alicesBalanceAfter < alicesBalanceBefore).to.be.true;44 // tslint:disable-next-line:no-unused-expression27 expect(bobsBalanceAfter > bobsBalanceBefore).to.be.true;45 expect(bobsBalanceAfter > bobsBalanceBefore).to.be.true;28 });46 });29 });47 });304831 it('Inability to pay fees error message is correct', async () => {49 it('Inability to pay fees error message is correct', async () => {32 await usingApi(async api => {50 await usingApi(async (api) => {33 // Find unused address51 // Find unused address34 const pk = await findUnusedAddress(api);52 const pk = await findUnusedAddress(api);355336 const error = console.error;37 const log = console.log;38 console.log = function () {};39 console.error = function () {};40 41 const badTransfer = api.tx.balances.transfer(bobsPublicKey, 1n);54 const badTransfer = api.tx.balances.transfer(bobsPublicKey, 1n);55 // const events = await submitTransactionAsync(pk, badTransfer);42 const badTransaction = async function () { 56 const badTransaction = async () => {43 const result = await submitTransactionAsync(pk, badTransfer);57 const events = await submitTransactionAsync(pk, badTransfer);58 const result = getCreateCollectionResult(events);59 // tslint:disable-next-line:no-unused-expression60 expect(result.success).to.be.false;44 };61 };45 await expect(badTransaction()).to.be.rejectedWith("Inability to pay some fees");62 expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees , e.g. account balance too low');4647 console.log = log;48 console.error = error;49 });63 });50 });64 });6566 it('Create collection, balance transfers and check balance', async () => {67 await usingApi(async (api) => {68 const Alice = privateKey('//Alice');69 const Bob = privateKey('//Bob');70 // nft71 const nftCollectionId = await createCollectionExpectSuccess();72 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');73 await transferExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob, 1, 'NFT');74 // fungible75 const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});76 const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');77 await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');78 // reFungible79 const reFungibleCollectionId = await80 createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});81 const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');82 await transferExpectSuccess(reFungibleCollectionId,83 newReFungibleTokenId, Alice, Bob, 1, 'ReFungible');84 });85 });51});86});8788describe('Negative Integration Test Transfer(recipient, collection_id, item_id, value)', () => {89 before(async () => {90 await usingApi(async (api: ApiPromise) => {91 Alice = privateKey('//Alice');92 Bob = privateKey('//Bob');93 Charlie = privateKey('//Charlie');94 });95 });96 it('Transfer with not existed collection_id', async () => {97 await usingApi(async (api) => {98 // nft99 const nftCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number;100 await transferExpectFail(nftCollectionCount + 1, 1, Alice, Bob, 1);101 // fungible102 const fungibleCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number;103 await transferExpectFail(fungibleCollectionCount + 1, 1, Alice, Bob, 1);104 // reFungible105 const reFungibleCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number;106 await transferExpectFail(reFungibleCollectionCount + 1, 1, Alice, Bob, 1);107 });108 });109 it('Transfer with deleted collection_id', async () => {110 // nft111 const nftCollectionId = await createCollectionExpectSuccess();112 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');113 await destroyCollectionExpectSuccess(nftCollectionId);114 await transferExpectFail(nftCollectionId, newNftTokenId, Alice, Bob, 1, 'NFT');115 // fungible116 const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});117 const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');118 await destroyCollectionExpectSuccess(fungibleCollectionId);119 await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');120 // reFungible121 const reFungibleCollectionId = await122 createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});123 const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');124 await destroyCollectionExpectSuccess(reFungibleCollectionId);125 await transferExpectFail(reFungibleCollectionId,126 newReFungibleTokenId, Alice, Bob, 1, 'ReFungible');127 });128 it('Transfer with not existed item_id', async () => {129 // nft130 const nftCollectionId = await createCollectionExpectSuccess();131 await transferExpectFail(nftCollectionId, 2, Alice, Bob, 1, 'NFT');132 // fungible133 const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});134 await transferExpectFail(fungibleCollectionId, 2, Alice, Bob, 1, 'Fungible');135 // reFungible136 const reFungibleCollectionId = await137 createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});138 await transferExpectFail(reFungibleCollectionId,139 2, Alice, Bob, 1, 'ReFungible');140 });141 it('Transfer with deleted item_id', async () => {142 // nft143 const nftCollectionId = await createCollectionExpectSuccess();144 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');145 await burnItemExpectSuccess(Alice, nftCollectionId, newNftTokenId, 1);146 await transferExpectFail(nftCollectionId, newNftTokenId, Alice, Bob, 1, 'NFT');147 // fungible148 const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});149 const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');150 await burnItemExpectSuccess(Alice, fungibleCollectionId, newFungibleTokenId, 10);151 await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');152 // reFungible153 const reFungibleCollectionId = await154 createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});155 const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');156 await burnItemExpectSuccess(Alice, reFungibleCollectionId, newReFungibleTokenId, 1);157 await transferExpectFail(reFungibleCollectionId,158 newReFungibleTokenId, Alice, Bob, 1, 'ReFungible');159 });160 it('Transfer with recipient that is not owner', async () => {161 // nft162 const nftCollectionId = await createCollectionExpectSuccess();163 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');164 await transferExpectFail(nftCollectionId, newNftTokenId, Charlie, Bob, 1, 'NFT');165 // fungible166 const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});167 const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');168 await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Charlie, Bob, 1, 'Fungible');169 // reFungible170 const reFungibleCollectionId = await171 createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});172 const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');173 await transferExpectFail(reFungibleCollectionId,174 newReFungibleTokenId, Charlie, Bob, 1, 'ReFungible');175 });176});52177tests/src/transferFrom.test.tsdiffbeforeafterbothno changes
tests/src/util/contracthelpers.tsdiffbeforeafterbothno changes
tests/src/util/helpers.tsdiffbeforeafterboth3// file 'LICENSE', which is part of this source code package.3// file 'LICENSE', which is part of this source code package.4//4//556import { ApiPromise, Keyring } from '@polkadot/api';7import { Enum, Struct } from '@polkadot/types/codec';8import type { AccountId, EventRecord } from '@polkadot/types/interfaces';9import { u128 } from '@polkadot/types/primitive';10import { IKeyringPair } from '@polkadot/types/types';11import { BigNumber } from 'bignumber.js';12import BN from 'bn.js';6import chai from 'chai';13import chai from 'chai';7import chaiAsPromised from 'chai-as-promised';14import chaiAsPromised from 'chai-as-promised';8import type { AccountId, EventRecord } from '@polkadot/types/interfaces';15import { alicesPublicKey, nullPublicKey } from '../accounts';9import { ApiPromise, Keyring } from "@polkadot/api";10import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from "../substrate/substrate-api";11import privateKey from '../substrate/privateKey';16import privateKey from '../substrate/privateKey';12import { alicesPublicKey, nullPublicKey } from "../accounts";17import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from '../substrate/substrate-api';13import { strToUTF16, utf16ToStr, hexToStr } from './util';14import { IKeyringPair } from '@polkadot/types/types';15import { BigNumber } from 'bignumber.js';16import { Struct, Enum } from '@polkadot/types/codec';17import { u128 } from '@polkadot/types/primitive';18import { ICollectionInterface } from '../types';18import { ICollectionInterface } from '../types';19import BN from "bn.js";19import { hexToStr, strToUTF16, utf16ToStr } from './util';202021chai.use(chaiAsPromised);21chai.use(chaiAsPromised);22const expect = chai.expect;22const expect = chai.expect;25 success: boolean,25 success: boolean,26};26};272728type CreateCollectionResult = {28interface CreateCollectionResult {29 success: boolean,29 success: boolean;30 collectionId: number30 collectionId: number;31};31}323233type CreateItemResult = {33interface CreateItemResult {34 success: boolean,34 success: boolean;35 collectionId: number,35 collectionId: number;36 itemId: number36 itemId: number;37};37}383839interface IReFungibleOwner {40 Fraction: BN;41 Owner: number[];42}4344interface ITokenDataType {45 Owner: number[];46 ConstData: number[];47 VariableData: number[];48}4950interface IFungibleTokenDataType {51 Value: BN;52}5354interface IReFungibleTokenDataType {55 Owner: IReFungibleOwner[];56 ConstData: number[];57 VariableData: number[];58}5939export function getGenericResult(events: EventRecord[]): GenericResult {60export function getGenericResult(events: EventRecord[]): GenericResult {40 let result: GenericResult = {61 const result: GenericResult = {41 success: false62 success: false,42 }63 };43 events.forEach(({ phase, event: { data, method, section } }) => {64 events.forEach(({ phase, event: { data, method, section } }) => {44 // console.log(` ${phase}: ${section}.${method}:: ${data}`);65 // console.log(` ${phase}: ${section}.${method}:: ${data}`);45 if (method == 'ExtrinsicSuccess') {66 if (method === 'ExtrinsicSuccess') {46 result.success = true;67 result.success = true;47 }68 }48 });69 });60 collectionId = parseInt(data[0].toString());81 collectionId = parseInt(data[0].toString());61 }82 }62 });83 });63 let result: CreateCollectionResult = {84 const result: CreateCollectionResult = {64 success,85 success,65 collectionId86 collectionId,66 }87 };67 return result;88 return result;68}89}699080 itemId = parseInt(data[1].toString());101 itemId = parseInt(data[1].toString());81 }102 }82 });103 });83 let result: CreateItemResult = {104 const result: CreateItemResult = {84 success,105 success,85 collectionId,106 collectionId,86 itemId107 itemId,87 }108 };88 return result;109 return result;89}110}9011191export type CollectionMode = 'NFT' | 'Fungible' | 'ReFungible';112interface Invalid {113 type: 'Invalid';114}115116interface Nft {117 type: 'NFT';118}119120interface Fungible {121 type: 'Fungible';122 decimalPoints: number;123}124125interface ReFungible {126 type: 'ReFungible';127 decimalPoints: number;128}129130interface Nft {131 type: 'NFT'132}133134interface Fungible {135 type: 'Fungible',136 decimalPoints: number137}138139interface ReFungible {140 type: 'ReFungible',141 decimalPoints: number142}143144type CollectionMode = Nft | Fungible | ReFungible | Invalid;14592export type CreateCollectionParams = {146export type CreateCollectionParams = {93 mode: CollectionMode,147 mode: CollectionMode,94 name: string,148 name: string,95 description: string,149 description: string,96 tokenPrefix: string150 tokenPrefix: string,97};151};9815299const defaultCreateCollectionParams: CreateCollectionParams = {153const defaultCreateCollectionParams: CreateCollectionParams = {154 description: 'description',155 mode: { type: 'NFT' },100 name: 'name',156 name: 'name',101 description: 'description',157 tokenPrefix: 'prefix',102 mode: 'NFT',103 tokenPrefix: 'prefix'104}158}105159106export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {160export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {109 let collectionId: number = 0;163 let collectionId: number = 0;110 await usingApi(async (api) => {164 await usingApi(async (api) => {111 // Get number of collections before the transaction165 // Get number of collections before the transaction112 const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());166 const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);113167114 // Run the CreateCollection transaction168 // Run the CreateCollection transaction115 const alicePrivateKey = privateKey('//Alice');169 const alicePrivateKey = privateKey('//Alice');170116 const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), mode);171 let modeprm = {};172 if (mode.type === 'NFT') {173 modeprm = {nft: null};174 } else if (mode.type === 'Fungible') {175 modeprm = {fungible: mode.decimalPoints};176 } else if (mode.type === 'ReFungible') {177 modeprm = {refungible: mode.decimalPoints};178 } else if (mode.type === 'Invalid') {179 modeprm = {invalid: null};180 }181182 const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);117 const events = await submitTransactionAsync(alicePrivateKey, tx);183 const events = await submitTransactionAsync(alicePrivateKey, tx);118 const result = getCreateCollectionResult(events);184 const result = getCreateCollectionResult(events);119185120 // Get number of collections after the transaction186 // Get number of collections after the transaction121 const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());187 const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);122188123 // Get the collection 189 // Get the collection124 const collection: any = (await api.query.nft.collection(result.collectionId)).toJSON();190 const collection: any = (await api.query.nft.collection(result.collectionId)).toJSON();125191126 // What to expect192 // What to expect193 // tslint:disable-next-line:no-unused-expression127 expect(result.success).to.be.true;194 expect(result.success).to.be.true;128 expect(result.collectionId).to.be.equal(BcollectionCount);195 expect(result.collectionId).to.be.equal(BcollectionCount);196 // tslint:disable-next-line:no-unused-expression129 expect(collection).to.be.not.null;197 expect(collection).to.be.not.null;130 expect(BcollectionCount).to.be.equal(AcollectionCount+1, 'Error: NFT collection NOT created.');198 expect(BcollectionCount).to.be.equal(AcollectionCount + 1, 'Error: NFT collection NOT created.');131 expect(collection.Owner).to.be.equal(alicesPublicKey);199 expect(collection.Owner).to.be.equal(alicesPublicKey);132 expect(utf16ToStr(collection.Name)).to.be.equal(name);200 expect(utf16ToStr(collection.Name)).to.be.equal(name);133 expect(utf16ToStr(collection.Description)).to.be.equal(description);201 expect(utf16ToStr(collection.Description)).to.be.equal(description);138206139 return collectionId;207 return collectionId;140}208}141 209142export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {210export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {143 const {name, description, mode, tokenPrefix } = {...defaultCreateCollectionParams, ...params};211 const {name, description, mode, tokenPrefix } = {...defaultCreateCollectionParams, ...params};144212213 let modeprm = {};214 if (mode.type === 'NFT') {215 modeprm = {nft: null};216 } else if (mode.type === 'Fungible') {217 modeprm = {fungible: mode.decimalPoints};218 } else if (mode.type === 'ReFungible') {219 modeprm = {refungible: mode.decimalPoints};220 } else if (mode.type === 'Invalid') {221 modeprm = {invalid: null};222 }223145 await usingApi(async (api) => {224 await usingApi(async (api) => {146 // Get number of collections before the transaction225 // Get number of collections before the transaction147 const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());226 const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());148227149 // Run the CreateCollection transaction228 // Run the CreateCollection transaction150 const alicePrivateKey = privateKey('//Alice');229 const alicePrivateKey = privateKey('//Alice');151 const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), mode);230 const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);152 const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;231 const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;153 const result = getCreateCollectionResult(events);232 const result = getCreateCollectionResult(events);154233155 // Get number of collections after the transaction234 // Get number of collections after the transaction156 const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());235 const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());157236158 // What to expect237 // What to expect238 // tslint:disable-next-line:no-unused-expression159 expect(result.success).to.be.false;239 expect(result.success).to.be.false;160 expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.');240 expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.');161 });241 });162}242}163 243164export async function findUnusedAddress(api: ApiPromise): Promise<IKeyringPair> {244export async function findUnusedAddress(api: ApiPromise): Promise<IKeyringPair> {165 let bal = new BigNumber(0);245 let bal = new BigNumber(0);166 let unused;246 let unused;170 unused = keyring.addFromUri(`//${randomSeed}`);250 unused = keyring.addFromUri(`//${randomSeed}`);171 bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString());251 bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString());172 } while (bal.toFixed() != '0');252 } while (bal.toFixed() != '0');173 return unused; 253 return unused;174}254}175255176function getDestroyResult(events: EventRecord[]): boolean {256function getDestroyResult(events: EventRecord[]): boolean {201 const events = await submitTransactionAsync(alicePrivateKey, tx);281 const events = await submitTransactionAsync(alicePrivateKey, tx);202 const result = getDestroyResult(events);282 const result = getDestroyResult(events);203283204 // Get the collection 284 // Get the collection205 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();285 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();206286207 // What to expect287 // What to expect220 const events = await submitTransactionAsync(alicePrivateKey, tx);300 const events = await submitTransactionAsync(alicePrivateKey, tx);221 const result = getGenericResult(events);301 const result = getGenericResult(events);222302223 // Get the collection 303 // Get the collection224 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();304 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();225305226 // What to expect306 // What to expect239 const events = await submitTransactionAsync(alicePrivateKey, tx);319 const events = await submitTransactionAsync(alicePrivateKey, tx);240 const result = getGenericResult(events);320 const result = getGenericResult(events);241321242 // Get the collection 322 // Get the collection243 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();323 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();244324245 // What to expect325 // What to expect278 const events = await submitTransactionAsync(sender, tx);358 const events = await submitTransactionAsync(sender, tx);279 const result = getGenericResult(events);359 const result = getGenericResult(events);280360281 // Get the collection 361 // Get the collection282 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();362 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();283363284 // What to expect364 // What to expect300380301export interface CreateFungibleData extends Struct {381export interface CreateFungibleData extends Struct {302 readonly value: u128;382 readonly value: u128;303};383}304384305export interface CreateReFungibleData extends Struct {};385export interface CreateReFungibleData extends Struct {}306export interface CreateNftData extends Struct {};386export interface CreateNftData extends Struct {}307387308export interface CreateItemData extends Enum {388export interface CreateItemData extends Enum {309 NFT: CreateNftData,389 NFT: CreateNftData;310 Fungible: CreateFungibleData,390 Fungible: CreateFungibleData;311 ReFungible: CreateReFungibleData391 ReFungible: CreateReFungibleData;312};392}313393314export async function createItemExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, owner: string = '') {394export async function burnItemExpectSuccess(owner: IKeyringPair, collectionId: number, tokenId: number, value = 0) {395 await usingApi(async (api) => {396 const tx = api.tx.nft.burnItem(collectionId, tokenId, value);397 const events = await submitTransactionAsync(owner, tx);398 const result = getGenericResult(events);399 // Get the item400 const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON();401 // What to expect402 // tslint:disable-next-line:no-unused-expression403 expect(result.success).to.be.true;404 // tslint:disable-next-line:no-unused-expression405 expect(item).to.be.not.null;406 expect(item.Owner).to.be.equal(nullPublicKey);407 });408}409410export async function411approveExpectSuccess(collectionId: number,412 tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number = 1) {413 await usingApi(async (api: ApiPromise) => {414 const allowanceBefore =415 await api.query.nft.allowances(collectionId, [tokenId, owner.address, approved.address]) as unknown as BN;416 const approveNftTx = await api.tx.nft.approve(approved.address, collectionId, tokenId, amount);417 const events = await submitTransactionAsync(owner, approveNftTx);418 const result = getCreateItemResult(events);419 // tslint:disable-next-line:no-unused-expression420 expect(result.success).to.be.true;421 const allowanceAfter =422 await api.query.nft.allowances(collectionId, [tokenId, owner.address, approved.address]) as unknown as BN;423 expect(allowanceAfter.toNumber() - allowanceBefore.toNumber()).to.be.equal(amount);424 });425}426427export async function428transferFromExpectSuccess(collectionId: number,429 tokenId: number,430 accountApproved: IKeyringPair,431 accountFrom: IKeyringPair,432 accountTo: IKeyringPair,433 value: number = 1,434 type: string = 'NFT') {435 await usingApi(async (api: ApiPromise) => {436 let balanceBefore = new BN(0);437 if (type === 'Fungible') {438 balanceBefore = await api.query.nft.balance(collectionId, accountTo.address) as unknown as BN;439 }440 const transferFromTx = await api.tx.nft.transferFrom(441 accountFrom.address, accountTo.address, collectionId, tokenId, value);442 const events = await submitTransactionAsync(accountFrom, transferFromTx);443 const result = getCreateItemResult(events);444 // tslint:disable-next-line:no-unused-expression445 expect(result.success).to.be.true;446 if (type === 'NFT') {447 const nftItemData = await api.query.nft.nftItemList(collectionId, tokenId) as unknown as ITokenDataType;448 expect(nftItemData.Owner.toString()).to.be.equal(accountTo.address);449 }450 if (type === 'Fungible') {451 const balanceAfter = await api.query.nft.balance(collectionId, accountTo.address) as unknown as BN;452 expect(balanceAfter.sub(balanceBefore).toNumber()).to.be.equal(value);453 }454 if (type === 'ReFungible') {455 const nftItemData =456 await api.query.nft.reFungibleItemList(collectionId, tokenId) as unknown as IReFungibleTokenDataType;457 expect(nftItemData.Owner[0].Owner.toString()).to.be.equal(accountTo.address);458 expect(nftItemData.Owner[0].Fraction.toNumber()).to.be.equal(value);459 }460 });461}462463export async function464transferFromExpectFail(collectionId: number,465 tokenId: number,466 accountApproved: IKeyringPair,467 accountFrom: IKeyringPair,468 accountTo: IKeyringPair,469 value: number = 1) {470 await usingApi(async (api: ApiPromise) => {471 const transferFromTx = await api.tx.nft.transferFrom(472 accountFrom.address, accountTo.address, collectionId, tokenId, value);473 const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected;474 const result = getCreateCollectionResult(events);475 // tslint:disable-next-line:no-unused-expression476 expect(result.success).to.be.false;477 });478}479480export async function481transferExpectSuccess(collectionId: number,482 tokenId: number,483 sender: IKeyringPair,484 recipient: IKeyringPair,485 value: number = 1,486 type: string = 'NFT') {487 await usingApi(async (api: ApiPromise) => {488 let balanceBefore = new BN(0);489 if (type === 'Fungible') {490 balanceBefore = await api.query.nft.balance(collectionId, recipient.address) as unknown as BN;491 }492 const transferTx = await api.tx.nft.transfer(recipient.address, collectionId, tokenId, value);493 const events = await submitTransactionAsync(sender, transferTx);494 const result = getCreateItemResult(events);495 // tslint:disable-next-line:no-unused-expression496 expect(result.success).to.be.true;497 if (type === 'NFT') {498 const nftItemData = await api.query.nft.nftItemList(collectionId, tokenId) as unknown as ITokenDataType;499 expect(nftItemData.Owner.toString()).to.be.equal(recipient.address);500 }501 if (type === 'Fungible') {502 const balanceAfter = await api.query.nft.balance(collectionId, recipient.address) as unknown as BN;503 expect(balanceAfter.sub(balanceBefore).toNumber()).to.be.equal(value);504 }505 if (type === 'ReFungible') {506 const nftItemData =507 await api.query.nft.reFungibleItemList(collectionId, tokenId) as unknown as IReFungibleTokenDataType;508 expect(nftItemData.Owner[0].Owner.toString()).to.be.equal(recipient.address);509 expect(nftItemData.Owner[0].Fraction.toNumber()).to.be.equal(value);510 }511 });512}513514export async function515transferExpectFail(collectionId: number,516 tokenId: number,517 sender: IKeyringPair,518 recipient: IKeyringPair,519 value: number = 1,520 type: string = 'NFT') {521 await usingApi(async (api: ApiPromise) => {522 const transferTx = await api.tx.nft.transfer(recipient.address, collectionId, tokenId, value);523 const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;524 if (events && Array.isArray(events)) {525 const result = getCreateCollectionResult(events);526 // tslint:disable-next-line:no-unused-expression527 expect(result.success).to.be.false;528 }529 });530}531532export async function533approveExpectFail(collectionId: number,534 tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number = 1) {535 await usingApi(async (api: ApiPromise) => {536 const approveNftTx = await api.tx.nft.approve(approved.address, collectionId, tokenId, amount);537 const events = await expect(submitTransactionExpectFailAsync(owner, approveNftTx)).to.be.rejected;538 const result = getCreateCollectionResult(events);539 // tslint:disable-next-line:no-unused-expression540 expect(result.success).to.be.false;541 });542}543544export async function createItemExpectSuccess(545 sender: IKeyringPair, collectionId: number, createMode: string, owner: string = '') {315 let newItemId: number = 0;546 let newItemId: number = 0;316 await usingApi(async (api) => {547 await usingApi(async (api) => {317 const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString());548 const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);318 const Aitem: any = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON(); 549 const Aitem: any = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON();319 const AItemBalance = new BigNumber(Aitem.Value);550 const AItemBalance = new BigNumber(Aitem.Value);320551321 if (owner === '') owner = sender.address;552 if (owner === '') {553 owner = sender.address;554 }322555323 let tx;556 let tx;324 if (createMode == 'Fungible') {557 if (createMode === 'Fungible') {325 let createData = {fungible: {value: 10}};558 const createData = {fungible: {value: 10}};326 tx = api.tx.nft.createItem(collectionId, owner, createData);559 tx = api.tx.nft.createItem(collectionId, owner, createData);327 }560 } else {328 else {329 tx = api.tx.nft.createItem(collectionId, owner, createMode);561 tx = api.tx.nft.createItem(collectionId, owner, createMode);330 }562 }331 const events = await submitTransactionAsync(sender, tx);563 const events = await submitTransactionAsync(sender, tx);332 const result = getCreateItemResult(events);564 const result = getCreateItemResult(events);333565334 const BItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString());566 const BItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);335 const Bitem: any = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON(); 567 const Bitem: any = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON();336 const BItemBalance = new BigNumber(Bitem.Value);568 const BItemBalance = new BigNumber(Bitem.Value);337569338 // What to expect570 // What to expect571 // tslint:disable-next-line:no-unused-expression339 expect(result.success).to.be.true;572 expect(result.success).to.be.true;340 if (createMode == 'Fungible') {573 if (createMode === 'Fungible') {341 expect(BItemBalance.minus(AItemBalance).toNumber()).to.be.equal(10);574 expect(BItemBalance.minus(AItemBalance).toNumber()).to.be.equal(10);575 } else {576 expect(BItemCount).to.be.equal(AItemCount + 1);342 }577 }343 else {344 expect(BItemCount).to.be.equal(AItemCount+1);345 }346 expect(collectionId).to.be.equal(result.collectionId);578 expect(collectionId).to.be.equal(result.collectionId);347 expect(BItemCount).to.be.equal(result.itemId);579 expect(BItemCount).to.be.equal(result.itemId);348 newItemId = result.itemId;580 newItemId = result.itemId;358 const events = await submitTransactionAsync(sender, tx);590 const events = await submitTransactionAsync(sender, tx);359 const result = getGenericResult(events);591 const result = getGenericResult(events);360592361 // Get the collection 593 // Get the collection362 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();594 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();363595364 // What to expect596 // What to expect597 // tslint:disable-next-line:no-unused-expression365 expect(result.success).to.be.true;598 expect(result.success).to.be.true;366 expect(collection.Access).to.be.equal('WhiteList');599 expect(collection.Access).to.be.equal('WhiteList');367 });600 });375 const events = await submitTransactionAsync(sender, tx);608 const events = await submitTransactionAsync(sender, tx);376 const result = getGenericResult(events);609 const result = getGenericResult(events);377610378 // Get the collection 611 // Get the collection379 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();612 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();380613381 // What to expect614 // What to expect387export async function addToWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string) {620export async function addToWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string) {388 await usingApi(async (api) => {621 await usingApi(async (api) => {389622623 const whiteListedBefore = (await api.query.nft.whiteList(collectionId, address)).toJSON();624390 // Run the transaction625 // Run the transaction391 const tx = api.tx.nft.addToWhiteList(collectionId, address);626 const tx = api.tx.nft.addToWhiteList(collectionId, address);392 const events = await submitTransactionAsync(sender, tx);627 const events = await submitTransactionAsync(sender, tx);393 const result = getGenericResult(events);628 const result = getGenericResult(events);394629395 // Get the collection 630 const whiteListedAfter = (await api.query.nft.whiteList(collectionId, address)).toJSON();396 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();397631398 // What to expect632 // What to expect633 // tslint:disable-next-line:no-unused-expression399 expect(result.success).to.be.true;634 expect(result.success).to.be.true;400 expect(collection.MintMode).to.be.equal(true);635 // tslint:disable-next-line: no-unused-expression636 expect(whiteListedBefore).to.be.false;637 // tslint:disable-next-line: no-unused-expression638 expect(whiteListedAfter).to.be.true;401 });639 });402}640}403641