git.delta.rocks / unique-network / refs/commits / d9abff92da75

difftreelog

Merge branch 'develop' into feature/NFTPAR-288

Greg Zaitsev2021-01-26parents: #513c1a0 #cd2216f.patch.diff
in: master

25 files changed

modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
323 CollectionNotFound,323 CollectionNotFound,
324 /// Item not exists.324 /// Item not exists.
325 TokenNotFound,325 TokenNotFound,
326 /// Admin not found
327 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>;
427429
428 /// Tokens transfer baskets430 /// Tokens transfer baskets
429 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;
812814
813 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);
815818
816 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 }
822822
823 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 };
10151015
10921092
1093 let sender = ensure_signed(origin)?;1093 let sender = ensure_signed(origin)?;
10941094
1095 Self::collection_exists(collection_id)?;
1096 Self::token_exists(collection_id, item_id, &sender)?;
1097
1095 // Transfer permissions check1098 // Transfer permissions check
1096 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 }
11621165
1163 // 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 0
1164 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)?;
1223
1220 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);
12211225
1225 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);
12271231
1228 Self::item_exists(collection_id, item_id, &target_collection.mode)?;
1229
1230 match target_collection.mode1232 match target_collection.mode
1231 {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())?;
13211323
1322 // check schema limit1324 // check schema limit
1323 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, "");
13241326
1325 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())?;
13521354
1353 // check schema limit1355 // check schema limit
1354 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, "");
13551357
1356 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();
16791681
1680 Self::add_token_index(collection_id, current_index, owner.clone())?;1682 Self::add_token_index(collection_id, current_index, &owner)?;
16811683
1682 <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);
16841686
1685 // Update balance1687 // Update balance
1686 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)?;
16981700
1699 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)?;
17011703
1702 <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>::TokenNotFound
1722 );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 = token
1725 .owner1727 .owner
1726 .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)?;
17311733
1732 // update balance1734 // update balance
1733 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);
17371739
1738 <ReFungibleItemList<T>>::remove(collection_id, item_id);1740 // Re-create owners list with sender removed
1741 let index = token
1742 .owner
1743 .iter()
1744 .position(|i| i.owner == *owner)
1745 .unwrap();
1746 token.owner.remove(index);
1747 let owner_count = token.owner.len();
17391748
1749 // Burn the token completely if this was the last (only) owner
1750 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 }
1756
1740 Ok(())1757 Ok(())
1741 }1758 }
17421759
1746 Error::<T>::TokenNotFound1763 Error::<T>::TokenNotFound
1747 );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)?;
17501767
1751 // update balance1768 // update balance
1752 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 }
18601877
1878 /// Check if token exists. In case of Fungible, check if there is an entry for
1879 /// the owner in fungible balances double map
1880 fn token_exists(
1881 collection_id: CollectionId,
1882 item_id: TokenId,
1883 owner: &T::AccountId
1884 ) -> DispatchResult {
1885 let target_collection = <Collection<T>>::get(collection_id);
1886 let exists = match target_collection.mode
1887 {
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 _ => false
1892 };
1893
1894 ensure!(exists == true, Error::<T>::TokenNotFound);
1895 Ok(())
1896 }
1897
1861 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>::TokenNotFound
1870 );
18711905
1872 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>::TokenNotFound
1903 );
19041935
1905 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_item
1941 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1972 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);
19421973
1943 // update index collection1974 // update index collection
1944 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_item
1966 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 }
19712002
1972 <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>::TokenNotFound
1987 );
19882016
1989 let mut item = <NftItemList<T>>::get(collection_id, item_id);2017 let mut item = <NftItemList<T>>::get(collection_id, item_id);
19902018
2010 <NftItemList<T>>::insert(collection_id, item_id, item);2038 <NftItemList<T>>::insert(collection_id, item_id, item);
20112039
2012 // update index collection2040 // update index collection
2013 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)?;
20142042
2015 Ok(())2043 Ok(())
2016 }2044 }
2017 2045
2018 fn item_exists(
2019 collection_id: CollectionId,
2020 item_id: TokenId,
2021 mode: &CollectionMode
2022 ) -> 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 }
2031
2032 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();
20912105
2092 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();
20942108
2095 <ItemListIndex>::insert(collection_id, current_index);2109 <ItemListIndex>::insert(collection_id, current_index);
20962110
2097 // Update balance2111 // Update balance
2098 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();
21082122
2109 Self::add_token_index(collection_id, current_index, (*owner).clone()).unwrap();2123 Self::add_token_index(collection_id, current_index, owner).unwrap();
21102124
2111 <ItemListIndex>::insert(collection_id, current_index);2125 <ItemListIndex>::insert(collection_id, current_index);
21122126
2125 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();
21272141
2128 Self::add_token_index(collection_id, current_index, owner.clone()).unwrap();2142 Self::add_token_index(collection_id, current_index, &owner).unwrap();
21292143
2130 <ItemListIndex>::insert(collection_id, current_index);2144 <ItemListIndex>::insert(collection_id, current_index);
21312145
2132 // Update balance2146 // Update balance
2133 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 }
21382152
2139 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 {
21402154
2141 // add to account limit2155 // add to account limit
2142 if <AccountItemCount<T>>::contains_key(owner.clone()) {2156 if <AccountItemCount<T>>::contains_key(owner) {
21432157
2144 // bound Owned tokens by a single address2158 // bound Owned tokens by a single address
2145 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);
21472161
2148 <AccountItemCount<T>>::insert(owner.clone(), count2162 <AccountItemCount<T>>::insert(owner.clone(), count
2153 <AccountItemCount<T>>::insert(owner.clone(), 1);2167 <AccountItemCount<T>>::insert(owner.clone(), 1);
2154 }2168 }
21552169
2156 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());
21602174
2161 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 }
21722185
2173 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 {
21812194
2182 // update counter2195 // update counter
2183 <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)?);
21872200
21882201
2189 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());
21932206
2194 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 }
21992212
2203 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)?;
23192332
2320 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 }
23322345
2333 // check free create limit2346 // check free create limit
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
1// Tests to be written here1// Tests to be written here
2use 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}
2528
28}31}
2932
30fn default_fungible_data () -> CreateFungibleData {33fn default_fungible_data () -> CreateFungibleData {
31 CreateFungibleData { }34 CreateFungibleData { value: 5 }
32}35}
3336
34fn 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());
240243
241 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}
244247
245#[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();
249252
250 create_test_collection(&CollectionMode::Fungible(3), 1);253// create_test_collection(&CollectionMode::Fungible(3), 1);
251254
252 let origin1 = Origin::signed(1);255// let origin1 = Origin::signed(1);
253256
254 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()];
255258
256 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// }
270273
271#[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());
283286
284 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]);
287289
288 // change owner scenario290 // change owner scenario
289 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]);
296295
297 // split item scenario296 // split item scenario
298 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]);
305300
306 // split item and new owner has account scenario301 // split item and new owner has account scenario
307 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}
316309
451 1), Error::<Test>::NoPermission);444 1), Error::<Test>::NoPermission);
452445
453 // do approve446 // do approve
454 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 5
459 approved: 2,
460 amount: 100000000
461 }
462 );452 );
463453
464 assert_ok!(TemplateModule::transfer_from(454 assert_ok!(TemplateModule::transfer_from(
469 1,459 1,
470 1460 1
471 ));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}
475465
505 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));495 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
506496
507 // do approve497 // do approve
508 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: 100000000
517 }
518 );
519502
520 assert_ok!(TemplateModule::transfer_from(503 assert_ok!(TemplateModule::transfer_from(
521 origin2.clone(),504 origin2.clone(),
525 1,508 1,
526 1509 1
527 ));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}
531514
560 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));543 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
561544
562 // do approve545 // do approve
563 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: 100000000
572 }
573 );
574550
575 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]);
587563
588 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 900
591 ApprovePermissions {567 );
592 approved: 3,
593 amount: 100000000
594 }
595 );
596 });568 });
597}569}
598570
609 let origin1 = Origin::signed(1);581 let origin1 = Origin::signed(1);
610 let origin2 = Origin::signed(2);582 let origin2 = Origin::signed(2);
611583
612 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]);
614585
615 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));
628599
629 // do approve600 // do approve
630 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 5
637 approved: 2,
638 amount: 100000000
639 }
640 );608 );
641609
642 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 4
649 ));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]);
654620
655 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: 100000000
661 }
662 );
663623
664 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 4
672 ));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]);
677
678 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 0);
679 });633 });
680}634}
681635
725 assert_eq!(TemplateModule::balance_count(1, 1), 1);679 assert_eq!(TemplateModule::balance_count(1, 1), 1);
726680
727 // burn item681 // burn item
728 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>::TokenNotFound
732 );686 );
733687
749 create_test_item(collection_id, &data.into());703 create_test_item(collection_id, &data.into());
750704
751 // 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);
753707
754 // burn item708 // burn item
755 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>::TokenNotFound
759 );713 );
760714
791 assert_eq!(TemplateModule::balance_count(1, 1), 1000);745 assert_eq!(TemplateModule::balance_count(1, 1), 1000);
792746
793 // burn item747 // burn item
794 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>::TokenNotFound
798 );752 );
799753
875829
876 // 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 // approve
899 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}
903857
914 create_test_item(collection_id, &data.into());868 create_test_item(collection_id, &data.into());
915869
916 // approve870 // approve
917 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);
919873
920 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));
12001154
1201 // do approve1155 // do approve
1202 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);
12041158
1205 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));
12641218
1265 // do approve1219 // do approve
1266 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);
12681222
1269 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::WhiteList
1299 ));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>::AddresNotInWhiteList
1303 );1257 );
1304 });1258 });
1305}1259}
13061260
1307// 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(|| {
13141268
1315 let origin1 = Origin::signed(1);1269 let origin1 = Origin::signed(1);
1270
1271 let data = default_nft_data();
1272 create_test_item(collection_id, &data.into());
1273
1316 assert_ok!(TemplateModule::set_public_access_mode(1274 assert_ok!(TemplateModule::set_public_access_mode(
1317 origin1.clone(),1275 origin1.clone(),
13211279
1322 // do approve1280 // do approve
1323 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>::AddresNotInWhiteList
1326 );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));
13751333
1376 // do approve1334 // do approve
1377 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);
13791337
1380 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 }));
17981771
1799 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 }));
18291805
1830 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 }));
18601839
1861 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 }));
19771959
1978 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 }));
20021987
20031988
modifiedtests/package.jsondiffbeforeafterboth
18 "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",
addedtests/src/addCollectionAdmin.test.tsdiffbeforeafterboth

no changes

addedtests/src/addToContractWhiteList.test.tsdiffbeforeafterboth

no changes

addedtests/src/addToWhiteList.test.tsdiffbeforeafterboth

no changes

addedtests/src/approve.test.tsdiffbeforeafterboth

no changes

addedtests/src/burnItem.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/confirmSponsorship.test.tsdiffbeforeafterboth
89 });89 });
9090
91 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');
9595
115 });115 });
116116
117 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');
121121
170 });170 });
171 });171 });
172172
173 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 });
211211
212 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');
216216
247 });247 });
248248
249 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');
253253
285 });285 });
286 });286 });
287
288 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');
292
293 // Enable collection white list
294 await enableWhiteListExpectSuccess(alice, collectionId);
295
296 // Enable public minting
297 await enablePublicMintingExpectSuccess(alice, collectionId);
298
299 await usingApi(async (api) => {
300 // Find unused address
301 const zeroBalance = await findUnusedAddress(api);
302
303 // Add zeroBalance address to white list
304 await addToWhiteListExpectSuccess(alice, collectionId, zeroBalance.address);
305
306 // Mint token using unused address as signer - gets sponsored
307 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);
308
309 // Second mint should fail
310 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());
323
324 // Try again after Zero gets some balance - now it should succeed
325 const balancetx = api.tx.balances.transfer(zeroBalance.address, 1e15);
326 await submitTransactionAsync(alice, balancetx);
327 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);
328
329 expect(BsponsorBalance.isEqualTo(AsponsorBalance)).to.be.true;
330 });
331 });
287332
288});333});
289334
modifiedtests/src/contracts.test.tsdiffbeforeafterboth
2import 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 getFlipValue
10} from "./util/contracthelpers";
1011
11chai.use(chaiAsPromised);12chai.use(chaiAsPromised);
12const expect = chai.expect;13const expect = chai.expect;
13import { BigNumber } from 'bignumber.js';
14import { findUnusedAddress } from './util/helpers';
1514
16const value = 0;15const value = 0;
17const gasLimit = 3000n * 1000000n;16const gasLimit = 3000n * 1000000n;
18const endowment = `1000000000000000`;
19const marketContractAddress = '5CYN9j3YvRkqxewoxeSvRbhAym4465C57uMmX5j4yz99L5H6';17const marketContractAddress = '5CYN9j3YvRkqxewoxeSvRbhAym4465C57uMmX5j4yz99L5H6';
20
21function deployBlueprint(alice: IKeyringPair, code: CodePromise): Promise<Blueprint> {
22 return new Promise<Blueprint>(async (resolve, reject) => {
23 const unsub = await code
24 .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 blueprint
28 resolve(result.blueprint);
29 unsub();
30 }
31 })
32 });
33}
34
35function deployContract(alice: IKeyringPair, blueprint: Blueprint) : Promise<any> {
36 return new Promise<any>(async (resolve, reject) => {
37 const endowment = 1000000000000000n;
38 const initValue = true;
39
40 const unsub = await blueprint.tx
41 .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}
50
51async function prepareDeployer(api: ApiPromise) {
52 // Find unused address
53 const deployer = await findUnusedAddress(api);
54
55 // Transfer balance to it
56 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);
62
63 return deployer;
64}
65
66export 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);
69
70 const deployer = await prepareDeployer(api);
71
72 const wasm = fs.readFileSync('./src/flipper/flipper.wasm');
73
74 const code = new CodePromise(api, abi, wasm);
75
76 const blueprint = await deployBlueprint(deployer, code);
77 const contract = (await deployContract(deployer, blueprint))['contract'] as Contract;
78
79 const initialGetResponse = await getFlipValue(contract, deployer);
80 expect(initialGetResponse).to.be.true;
81
82 return [contract, deployer];
83}
84
85async function getFlipValue(contract: Contract, deployer: IKeyringPair) {
86 const result = await contract.query.get(deployer.address, value, gasLimit);
87
88 if(!result.result.isSuccess) {
89 throw `Failed to get flipper value`;
90 }
91 return (result.result.asSuccess.data[0] == 0x00) ? false : true;
92}
9318
94describe('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 });
108
109 it(`Whitelisted account can call contract.`, async () => {
110 await usingApi(async api => {
111 const bob = privateKey("//Bob");
112
113 const [contract, deployer] = await deployFlipper(api);
114
115 let expectedFlipValue = await getFlipValue(contract, deployer);
116
117 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.`);
122
123 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();
131
132 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.`);
138
139 await deployerCanFlip();
140
141 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.`);
148
149 await deployerCanFlip();
150
151 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.`);
157
158 await deployerCanFlip();
159
160 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.`);
167
168 });
169 });
17033
171 it('Can initialize contract instance', async () => {34 it('Can initialize contract instance', async () => {
172 await usingApi(async (api) => {35 await usingApi(async (api) => {
modifiedtests/src/createCollection.test.tsdiffbeforeafterboth
5 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});
5960
modifiedtests/src/createItem.test.tsdiffbeforeafterboth
18 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});
modifiedtests/src/destroyCollection.test.tsdiffbeforeafterboth
14 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});
addedtests/src/removeCollectionAdmin.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/setCollectionLimits.test.tsdiffbeforeafterboth
32 });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});
modifiedtests/src/setCollectionSponsor.test.tsdiffbeforeafterboth
30 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 });
4040
addedtests/src/setPublicAccessMode.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/setSchemaVersion.test.tsdiffbeforeafterboth
35 });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-expression
100 expect(e).to.be.exist;
101 }*/
102 });96 });
103 });97 });
10498
119 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-expression
127 expect(e).to.be.exist;
128 }*/
129 });116 });
130 });117 });
131});118});
modifiedtests/src/substrate/get-balance.tsdiffbeforeafterboth
3// file 'LICENSE', which is part of this source code package.3// file 'LICENSE', which is part of this source code package.
4//4//
55
6import { 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';
99
10export 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}
1515
modifiedtests/src/substrate/substrate-api.tsdiffbeforeafterboth
6060
61export function submitTransactionAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {61export function
62submitTransactionAsync(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);
6667
67 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);
106
107 console.log('transactionStatus', transactionStatus, 'events', events);
106108
107 if (transactionStatus == TransactionStatus.Success) {109 if (transactionStatus == TransactionStatus.Success) {
108 resolve(events);110 resolve(events);
addedtests/src/toggleContractWhiteList.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/transfer.test.tsdiffbeforeafterboth
3// file 'LICENSE', which is part of this source code package.3// file 'LICENSE', which is part of this source code package.
4//4//
55
6import { 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';
22
23let Alice: IKeyringPair;
24let Bob: IKeyringPair;
25let Charlie: IKeyringPair;
1326
14describe('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]);
1831
19 const alicePrivateKey = privateKey('//Alice');32 const alicePrivateKey = privateKey('//Alice');
20 33
21 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-expression
38 expect(result.success).to.be.true;
2339
24 const [alicesBalanceAfter, bobsBalanceAfter] = await getBalance(api, [alicesPublicKey, bobsPublicKey]);40 const [alicesBalanceAfter, bobsBalanceAfter] = await getBalance(api, [alicesPublicKey, bobsPublicKey]);
2541
42 // tslint:disable-next-line:no-unused-expression
26 expect(alicesBalanceAfter < alicesBalanceBefore).to.be.true;43 expect(alicesBalanceAfter < alicesBalanceBefore).to.be.true;
44 // tslint:disable-next-line:no-unused-expression
27 expect(bobsBalanceAfter > bobsBalanceBefore).to.be.true;45 expect(bobsBalanceAfter > bobsBalanceBefore).to.be.true;
28 });46 });
29 });47 });
3048
31 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 address
34 const pk = await findUnusedAddress(api);52 const pk = await findUnusedAddress(api);
3553
36 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-expression
60 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');
46
47 console.log = log;
48 console.error = error;
49 });63 });
50 });64 });
65
66 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 // nft
71 const nftCollectionId = await createCollectionExpectSuccess();
72 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
73 await transferExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob, 1, 'NFT');
74 // fungible
75 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 // reFungible
79 const reFungibleCollectionId = await
80 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});
87
88describe('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 // nft
99 const nftCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number;
100 await transferExpectFail(nftCollectionCount + 1, 1, Alice, Bob, 1);
101 // fungible
102 const fungibleCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number;
103 await transferExpectFail(fungibleCollectionCount + 1, 1, Alice, Bob, 1);
104 // reFungible
105 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 // nft
111 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 // fungible
116 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 // reFungible
121 const reFungibleCollectionId = await
122 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 // nft
130 const nftCollectionId = await createCollectionExpectSuccess();
131 await transferExpectFail(nftCollectionId, 2, Alice, Bob, 1, 'NFT');
132 // fungible
133 const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
134 await transferExpectFail(fungibleCollectionId, 2, Alice, Bob, 1, 'Fungible');
135 // reFungible
136 const reFungibleCollectionId = await
137 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 // nft
143 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 // fungible
148 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 // reFungible
153 const reFungibleCollectionId = await
154 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 // nft
162 const nftCollectionId = await createCollectionExpectSuccess();
163 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
164 await transferExpectFail(nftCollectionId, newNftTokenId, Charlie, Bob, 1, 'NFT');
165 // fungible
166 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 // reFungible
170 const reFungibleCollectionId = await
171 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});
52177
addedtests/src/transferFrom.test.tsdiffbeforeafterboth

no changes

addedtests/src/util/contracthelpers.tsdiffbeforeafterboth

no changes

modifiedtests/src/util/helpers.tsdiffbeforeafterboth
3// file 'LICENSE', which is part of this source code package.3// file 'LICENSE', which is part of this source code package.
4//4//
55
6import { 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';
2020
21chai.use(chaiAsPromised);21chai.use(chaiAsPromised);
22const expect = chai.expect;22const expect = chai.expect;
25 success: boolean,25 success: boolean,
26};26};
2727
28type CreateCollectionResult = {28interface CreateCollectionResult {
29 success: boolean,29 success: boolean;
30 collectionId: number30 collectionId: number;
31};31}
3232
33type CreateItemResult = {33interface CreateItemResult {
34 success: boolean,34 success: boolean;
35 collectionId: number,35 collectionId: number;
36 itemId: number36 itemId: number;
37};37}
3838
39interface IReFungibleOwner {
40 Fraction: BN;
41 Owner: number[];
42}
43
44interface ITokenDataType {
45 Owner: number[];
46 ConstData: number[];
47 VariableData: number[];
48}
49
50interface IFungibleTokenDataType {
51 Value: BN;
52}
53
54interface IReFungibleTokenDataType {
55 Owner: IReFungibleOwner[];
56 ConstData: number[];
57 VariableData: number[];
58}
59
39export 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}
6990
80 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}
90111
91export type CollectionMode = 'NFT' | 'Fungible' | 'ReFungible';112interface Invalid {
113 type: 'Invalid';
114}
115
116interface Nft {
117 type: 'NFT';
118}
119
120interface Fungible {
121 type: 'Fungible';
122 decimalPoints: number;
123}
124
125interface ReFungible {
126 type: 'ReFungible';
127 decimalPoints: number;
128}
129
130interface Nft {
131 type: 'NFT'
132}
133
134interface Fungible {
135 type: 'Fungible',
136 decimalPoints: number
137}
138
139interface ReFungible {
140 type: 'ReFungible',
141 decimalPoints: number
142}
143
144type CollectionMode = Nft | Fungible | ReFungible | Invalid;
145
92export 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};
98152
99const 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}
105159
106export 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 transaction
112 const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());166 const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);
113167
114 // Run the CreateCollection transaction168 // Run the CreateCollection transaction
115 const alicePrivateKey = privateKey('//Alice');169 const alicePrivateKey = privateKey('//Alice');
170
116 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 }
181
182 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);
119185
120 // Get number of collections after the transaction186 // Get number of collections after the transaction
121 const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());187 const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);
122188
123 // Get the collection 189 // Get the collection
124 const collection: any = (await api.query.nft.collection(result.collectionId)).toJSON();190 const collection: any = (await api.query.nft.collection(result.collectionId)).toJSON();
125191
126 // What to expect192 // What to expect
193 // tslint:disable-next-line:no-unused-expression
127 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-expression
129 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);
138206
139 return collectionId;207 return collectionId;
140}208}
141 209
142export 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};
144212
213 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 }
223
145 await usingApi(async (api) => {224 await usingApi(async (api) => {
146 // Get number of collections before the transaction225 // Get number of collections before the transaction
147 const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());226 const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());
148227
149 // Run the CreateCollection transaction228 // Run the CreateCollection transaction
150 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);
154233
155 // Get number of collections after the transaction234 // Get number of collections after the transaction
156 const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());235 const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());
157236
158 // What to expect237 // What to expect
238 // tslint:disable-next-line:no-unused-expression
159 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 243
164export 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}
175255
176function 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);
203283
204 // Get the collection 284 // Get the collection
205 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();285 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
206286
207 // What to expect287 // What to expect
220 const events = await submitTransactionAsync(alicePrivateKey, tx);300 const events = await submitTransactionAsync(alicePrivateKey, tx);
221 const result = getGenericResult(events);301 const result = getGenericResult(events);
222302
223 // Get the collection 303 // Get the collection
224 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();304 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
225305
226 // What to expect306 // What to expect
239 const events = await submitTransactionAsync(alicePrivateKey, tx);319 const events = await submitTransactionAsync(alicePrivateKey, tx);
240 const result = getGenericResult(events);320 const result = getGenericResult(events);
241321
242 // Get the collection 322 // Get the collection
243 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();323 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
244324
245 // What to expect325 // What to expect
278 const events = await submitTransactionAsync(sender, tx);358 const events = await submitTransactionAsync(sender, tx);
279 const result = getGenericResult(events);359 const result = getGenericResult(events);
280360
281 // Get the collection 361 // Get the collection
282 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();362 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
283363
284 // What to expect364 // What to expect
300380
301export interface CreateFungibleData extends Struct {381export interface CreateFungibleData extends Struct {
302 readonly value: u128;382 readonly value: u128;
303};383}
304384
305export interface CreateReFungibleData extends Struct {};385export interface CreateReFungibleData extends Struct {}
306export interface CreateNftData extends Struct {};386export interface CreateNftData extends Struct {}
307387
308export 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}
313393
314export 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 item
400 const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON();
401 // What to expect
402 // tslint:disable-next-line:no-unused-expression
403 expect(result.success).to.be.true;
404 // tslint:disable-next-line:no-unused-expression
405 expect(item).to.be.not.null;
406 expect(item.Owner).to.be.equal(nullPublicKey);
407 });
408}
409
410export async function
411approveExpectSuccess(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-expression
420 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}
426
427export async function
428transferFromExpectSuccess(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-expression
445 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}
462
463export async function
464transferFromExpectFail(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-expression
476 expect(result.success).to.be.false;
477 });
478}
479
480export async function
481transferExpectSuccess(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-expression
496 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}
513
514export async function
515transferExpectFail(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-expression
527 expect(result.success).to.be.false;
528 }
529 });
530}
531
532export async function
533approveExpectFail(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-expression
540 expect(result.success).to.be.false;
541 });
542}
543
544export 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);
320551
321 if (owner === '') owner = sender.address;552 if (owner === '') {
553 owner = sender.address;
554 }
322555
323 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);
333565
334 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);
337569
338 // What to expect570 // What to expect
571 // tslint:disable-next-line:no-unused-expression
339 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);
360592
361 // Get the collection 593 // Get the collection
362 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();594 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
363595
364 // What to expect596 // What to expect
597 // tslint:disable-next-line:no-unused-expression
365 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);
377610
378 // Get the collection 611 // Get the collection
379 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();612 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
380613
381 // What to expect614 // What to expect
387export 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) => {
389622
623 const whiteListedBefore = (await api.query.nft.whiteList(collectionId, address)).toJSON();
624
390 // Run the transaction625 // Run the transaction
391 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);
394629
395 // 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();
397631
398 // What to expect632 // What to expect
633 // tslint:disable-next-line:no-unused-expression
399 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-expression
636 expect(whiteListedBefore).to.be.false;
637 // tslint:disable-next-line: no-unused-expression
638 expect(whiteListedAfter).to.be.true;
401 });639 });
402}640}
403641