difftreelog
refactor optional collections related review
in: master
1 file changed
pallets/nft/src/lib.rsdiffbeforeafterboth199 }199 }200}200}201201202#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]202#[derive(Encode, Decode, Debug, Clone, PartialEq)]203#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]203#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]204pub struct NftItemType<AccountId> {204pub struct NftItemType<AccountId> {205 pub owner: AccountId,205 pub owner: AccountId,213 pub value: u128,213 pub value: u128,214}214}215215216#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]216#[derive(Encode, Decode, Debug, Clone, PartialEq)]217#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]217#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]218pub struct ReFungibleItemType<AccountId> {218pub struct ReFungibleItemType<AccountId> {219 pub owner: Vec<Ownership<AccountId>>,219 pub owner: Vec<Ownership<AccountId>>,537537538 /// Amount of items which spender can transfer out of owners account (via transferFrom)538 /// Amount of items which spender can transfer out of owners account (via transferFrom)539 /// Collection id (controlled?2), (token id (controlled ?2) + owner account id (real) + spender account id (controlled?3))539 /// Collection id (controlled?2), (token id (controlled ?2) + owner account id (real) + spender account id (controlled?3))540 /// TODO: Off chain worker should remove from this map when token gets removed540 pub Allowances get(fn approved): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) (TokenId, T::AccountId, T::AccountId) => u128;541 pub Allowances get(fn approved): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) (TokenId, T::AccountId, T::AccountId) => u128;541542542 //#region Item collections543 //#region Item collections543 /// Collection id (controlled?2), token id (controlled?1)544 /// Collection id (controlled?2), token id (controlled?1)544 pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => NftItemType<T::AccountId>;545 pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<NftItemType<T::AccountId>>;545 /// Collection id (controlled?2), owner (controlled?2)546 /// Collection id (controlled?2), owner (controlled?2)546 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => FungibleItemType;547 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => FungibleItemType;547 /// Collection id (controlled?2), token id (controlled?1)548 /// Collection id (controlled?2), token id (controlled?1)548 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => ReFungibleItemType<T::AccountId>;549 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<ReFungibleItemType<T::AccountId>>;549 //#endregion550 //#endregion550551551 //#region Index list552 //#region Index list555556556 //#region Tokens transfer rate limit baskets557 //#region Tokens transfer rate limit baskets557 /// (Collection id (controlled?2), who created (real))558 /// (Collection id (controlled?2), who created (real))559 /// TODO: Off chain worker should remove from this map when collection gets removed558 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => T::BlockNumber;560 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => T::BlockNumber;559 /// Collection id (controlled?2), token id (controlled?2)561 /// Collection id (controlled?2), token id (controlled?2)560 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;562 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;570 572 571 //#region Contract Sponsorship and Ownership573 //#region Contract Sponsorship and Ownership572 /// Contract address (real)574 /// Contract address (real)573 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;575 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => Option<T::AccountId>;574 /// Contract address (real)576 /// Contract address (real)575 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;577 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;576 /// (Contract address(real), caller (real))578 /// (Contract address(real), caller (real))968 let sender = ensure_signed(origin)?;970 let sender = ensure_signed(origin)?;969 let collection = Self::get_collection(collection_id)?;971 let collection = Self::get_collection(collection_id)?;970 Self::check_owner_or_admin_permissions(&collection, sender)?;972 Self::check_owner_or_admin_permissions(&collection, sender)?;971 let mut admin_arr: Vec<T::AccountId> = Vec::new();973 let mut admin_arr = <AdminList<T>>::get(collection_id);972974973 if <AdminList<T>>::contains_key(collection_id)975 match admin_arr.binary_search(&new_admin_id) {974 {976 Ok(_) => {},975 admin_arr = <AdminList<T>>::get(collection_id);977 Err(idx) => {978 let limits = ChainLimit::get();976 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);979 ensure!(admin_arr.len() < limits.collections_admins_limit as usize, Error::<T>::CollectionAdminsLimitExceeded);980 admin_arr.insert(idx, new_admin_id);981 <AdminList<T>>::insert(collection_id, admin_arr);982 }977 }983 }978979 // Number of collection admins980 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);981982 admin_arr.push(new_admin_id);983 <AdminList<T>>::insert(collection_id, admin_arr);984985 Ok(())984 Ok(())986 }985 }9879861004 let sender = ensure_signed(origin)?;1003 let sender = ensure_signed(origin)?;1005 let collection = Self::get_collection(collection_id)?;1004 let collection = Self::get_collection(collection_id)?;1006 Self::check_owner_or_admin_permissions(&collection, sender)?;1005 Self::check_owner_or_admin_permissions(&collection, sender)?;1007 ensure!(<AdminList<T>>::contains_key(collection_id), Error::<T>::AdminNotFound);10081009 let mut admin_arr = <AdminList<T>>::get(collection_id);1006 let mut admin_arr = <AdminList<T>>::get(collection_id);1010 admin_arr.retain(|i| *i != account_id);1011 <AdminList<T>>::insert(collection_id, admin_arr);101210071008 match admin_arr.binary_search(&account_id) {1009 Ok(idx) => {1010 admin_arr.remove(idx);1011 <AdminList<T>>::insert(collection_id, admin_arr);1012 },1013 Err(_) => {}1014 }1013 Ok(())1015 Ok(())1014 }1016 }101510171267 let sender = ensure_signed(origin)?;1269 let sender = ensure_signed(origin)?;1268 let target_collection = Self::get_collection(collection_id)?;1270 let target_collection = Self::get_collection(collection_id)?;126912711270 Self::token_exists(&target_collection, item_id, &sender)?;1272 Self::token_exists(&target_collection, item_id)?;127112731272 // Transfer permissions check1274 // Transfer permissions check1273 let bypasses_limits = target_collection.limits.owner_can_transfer &&1275 let bypasses_limits = target_collection.limits.owner_can_transfer &&1419 let sender = ensure_signed(origin)?;1421 let sender = ensure_signed(origin)?;1420 1422 1421 let target_collection = Self::get_collection(collection_id)?;1423 let target_collection = Self::get_collection(collection_id)?;1422 Self::token_exists(&target_collection, item_id, &sender)?;1424 Self::token_exists(&target_collection, item_id)?;142314251424 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1426 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);142514271668 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1670 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());166916711670 Self::ensure_contract_owned(sender, &contract_address)?;1672 Self::ensure_contract_owned(sender, &contract_address)?;1671 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1673 if enable {1674 <ContractWhiteListEnabled<T>>::insert(contract_address, true);1675 } else {1676 <ContractWhiteListEnabled<T>>::remove(contract_address);1677 }1672 Ok(())1678 Ok(())1673 }1679 }1674 1680 1901 let collection_id = collection.id;1907 let collection_id = collection.id;190219081903 // Does new owner already have an account?1909 // Does new owner already have an account?1904 let mut balance: u128 = 0;1910 let balance: u128 = <FungibleItemList<T>>::get(collection_id, owner).value;1905 if <FungibleItemList<T>>::contains_key(collection_id, owner) {1906 balance = <FungibleItemList<T>>::get(collection_id, owner).value;1907 } 190819111909 // Mint 1912 // Mint 1910 let item = FungibleItemType {1913 let item = FungibleItemType {1911 value: balance + value1914 value: balance.checked_add(value).ok_or(Error::<T>::NumOverflow)?,1912 };1915 };1913 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);1916 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);191419171984 ) -> DispatchResult {1987 ) -> DispatchResult {1985 let collection_id = collection.id;1988 let collection_id = collection.id;198619891987 ensure!(1990 let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id)1988 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1989 Error::<T>::TokenNotFound1991 .ok_or(Error::<T>::TokenNotFound)?;1990 );1991 let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id);1992 let rft_balance = token1992 let rft_balance = token1993 .owner1993 .owner1994 .iter()1994 .iter()2026 fn burn_nft_item(collection: &CollectionHandle<T>, item_id: TokenId) -> DispatchResult {2026 fn burn_nft_item(collection: &CollectionHandle<T>, item_id: TokenId) -> DispatchResult {2027 let collection_id = collection.id;2027 let collection_id = collection.id;202820282029 ensure!(2029 let item = <NftItemList<T>>::get(collection_id, item_id)2030 <NftItemList<T>>::contains_key(collection_id, item_id),2031 Error::<T>::TokenNotFound2030 .ok_or(Error::<T>::TokenNotFound)?;2032 );2033 let item = <NftItemList<T>>::get(collection_id, item_id);2034 Self::remove_token_index(collection_id, item_id, &item.owner)?;2031 Self::remove_token_index(collection_id, item_id, &item.owner)?;203520322036 // update balance2033 // update balance2047 fn burn_fungible_item(owner: &T::AccountId, collection: &CollectionHandle<T>, value: u128) -> DispatchResult {2044 fn burn_fungible_item(owner: &T::AccountId, collection: &CollectionHandle<T>, value: u128) -> DispatchResult {2048 let collection_id = collection.id;2045 let collection_id = collection.id;204920462050 ensure!(2051 <FungibleItemList<T>>::contains_key(collection_id, owner),2052 Error::<T>::TokenNotFound2053 );2054 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);2047 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);2055 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);2048 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);205620492094 }2087 }209520882096 fn is_owner_or_admin_permissions(collection: &CollectionHandle<T>, subject: T::AccountId) -> bool {2089 fn is_owner_or_admin_permissions(collection: &CollectionHandle<T>, subject: T::AccountId) -> bool {2097 let mut result: bool = subject == collection.owner;2090 subject == collection.owner || <AdminList<T>>::get(collection.id).contains(&subject)2098 let exists = <AdminList<T>>::contains_key(collection.id);20992100 if !result & exists {2101 if <AdminList<T>>::get(collection.id).contains(&subject) {2102 result = true2103 }2104 }21052106 result2107 }2091 }210820922109 fn check_owner_or_admin_permissions(2093 fn check_owner_or_admin_permissions(2110 collection: &CollectionHandle<T>,2094 collection: &CollectionHandle<T>,2111 subject: T::AccountId,2095 subject: T::AccountId,2112 ) -> DispatchResult {2096 ) -> DispatchResult {2113 let result = Self::is_owner_or_admin_permissions(collection, subject.clone());2097 ensure!(Self::is_owner_or_admin_permissions(collection, subject), Error::<T>::NoPermission);211420982115 ensure!(2116 result,2117 Error::<T>::NoPermission2118 );2119 Ok(())2099 Ok(())2120 }2100 }212121012127 let collection_id = target_collection.id;2107 let collection_id = target_collection.id;212821082129 match target_collection.mode {2109 match target_collection.mode {2130 CollectionMode::NFT => {2110 CollectionMode::NFT => (<NftItemList<T>>::get(collection_id, item_id)?.owner == subject)2131 if <NftItemList<T>>::get(collection_id, item_id).owner == subject {2132 return Some(1)2111 .then(|| 1),2133 }2134 None2135 },2136 CollectionMode::Fungible(_) => {2112 CollectionMode::Fungible(_) => Some(<FungibleItemList<T>>::get(collection_id, &subject)2137 if <FungibleItemList<T>>::contains_key(collection_id, &subject) {2138 return Some(<FungibleItemList<T>>::get(collection_id, &subject)2139 .value);2113 .value),2140 }2141 None2142 },2143 CollectionMode::ReFungible => <ReFungibleItemList<T>>::get(collection_id, item_id)2114 CollectionMode::ReFungible => <ReFungibleItemList<T>>::get(collection_id, item_id)?2144 .owner2115 .owner2145 .iter()2116 .iter()2146 .find(|i| i.owner == subject)2117 .find(|i| i.owner == subject)2150 }2121 }215121222152 fn is_item_owner(subject: T::AccountId, target_collection: &CollectionHandle<T>, item_id: TokenId) -> bool {2123 fn is_item_owner(subject: T::AccountId, target_collection: &CollectionHandle<T>, item_id: TokenId) -> bool {2153 let collection_id = target_collection.id;21542155 match target_collection.mode {2124 match target_collection.mode {2156 CollectionMode::NFT => {2125 CollectionMode::Fungible(_) => true,2157 <NftItemList<T>>::get(collection_id, item_id).owner == subject2158 }2159 CollectionMode::Fungible(_) => {2160 <FungibleItemList<T>>::contains_key(collection_id, &subject)2161 }2126 _ => Self::owned_amount(subject, target_collection, item_id).is_some(),2162 CollectionMode::ReFungible => {2163 <ReFungibleItemList<T>>::get(collection_id, item_id)2164 .owner2165 .iter()2166 .any(|i| i.owner == subject)2167 }2168 CollectionMode::Invalid => false,2169 }2127 }2170 }2128 }217121292183 fn token_exists(2141 fn token_exists(2184 target_collection: &CollectionHandle<T>,2142 target_collection: &CollectionHandle<T>,2185 item_id: TokenId,2143 item_id: TokenId,2186 owner: &T::AccountId2187 ) -> DispatchResult {2144 ) -> DispatchResult {2188 let collection_id = target_collection.id;2145 let collection_id = target_collection.id;2189 let exists = match target_collection.mode2146 let exists = match target_collection.mode2190 {2147 {2191 CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),2148 CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),2192 CollectionMode::Fungible(_) => <FungibleItemList<T>>::contains_key(collection_id, owner),2149 CollectionMode::Fungible(_) => true,2193 CollectionMode::ReFungible => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),2150 CollectionMode::ReFungible => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),2194 _ => false2151 _ => false2195 };2152 };2205 recipient: &T::AccountId,2162 recipient: &T::AccountId,2206 ) -> DispatchResult {2163 ) -> DispatchResult {2207 let collection_id = collection.id;2164 let collection_id = collection.id;2208 Self::token_exists(&collection, 0, owner)?;220921652210 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);2166 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);2211 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);2167 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);2236 new_owner: T::AccountId,2192 new_owner: T::AccountId,2237 ) -> DispatchResult {2193 ) -> DispatchResult {2238 let collection_id = collection.id;2194 let collection_id = collection.id;2239 Self::token_exists(collection, item_id, &owner)?;2195 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id)2196 .ok_or(Error::<T>::TokenNotFound)?;224021972241 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);2242 let item = full_item2198 let item = full_item2243 .owner2199 .owner2244 .iter()2200 .iter()2318 new_owner: T::AccountId,2274 new_owner: T::AccountId,2319 ) -> DispatchResult {2275 ) -> DispatchResult {2320 let collection_id = collection.id;2276 let collection_id = collection.id;2321 Self::token_exists(&collection, item_id, &sender)?;2277 let mut item = <NftItemList<T>>::get(collection_id, item_id)2278 .ok_or(Error::<T>::TokenNotFound)?;232222792323 let mut item = <NftItemList<T>>::get(collection_id, item_id);23242325 ensure!(2280 ensure!(2326 sender == item.owner,2281 sender == item.owner,2327 Error::<T>::MustBeTokenOwner2282 Error::<T>::MustBeTokenOwner2355 data: Vec<u8>2310 data: Vec<u8>2356 ) -> DispatchResult {2311 ) -> DispatchResult {2357 let collection_id = collection.id;2312 let collection_id = collection.id;2358 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);2313 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id)2314 .ok_or(Error::<T>::TokenNotFound)?;235923152360 item.variable_data = data;2316 item.variable_data = data;236123172370 data: Vec<u8>2326 data: Vec<u8>2371 ) -> DispatchResult {2327 ) -> DispatchResult {2372 let collection_id = collection.id;2328 let collection_id = collection.id;2373 let mut item = <NftItemList<T>>::get(collection_id, item_id);2329 let mut item = <NftItemList<T>>::get(collection_id, item_id)2330 .ok_or(Error::<T>::TokenNotFound)?;2374 2331 2375 item.variable_data = data;2332 item.variable_data = data;237623332533 }2490 }2534 2491 2535 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2492 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2536 if <ContractOwner<T>>::contains_key(contract.clone()) {2493 ensure!(<ContractOwner<T>>::get(contract) == Some(account), Error::<T>::NoPermission);2537 let owner = <ContractOwner<T>>::get(contract);2538 ensure!(account == owner, Error::<T>::NoPermission);2539 } else {2540 fail!(Error::<T>::NoPermission);2541 }254224942543 Ok(())2495 Ok(())2544 }2496 }278727392788 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());2740 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());278927412790 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2742 let owned_contract = <ContractOwner<T>>::get(called_contract.clone()).as_ref() == Some(who);2791 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2792 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2743 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone());2793 2744 2794 if !owned_contract && white_list_enabled {2745 if !owned_contract && white_list_enabled {2795 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2746 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {