difftreelog
feat add token children
in: master
6 files changed
pallets/common/src/lib.rsdiffbeforeafterboth1237 budget: &dyn Budget,1237 budget: &dyn Budget,1238 ) -> DispatchResult;1238 ) -> DispatchResult;12391240 fn nest(1241 &self,1242 _under: TokenId,1243 _to_nest: (CollectionId, TokenId)1244 ) {}12451246 fn unnest(1247 &self,1248 _under: TokenId,1249 _to_nest: (CollectionId, TokenId)1250 ) {}123912511240 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;1252 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;1241 fn collection_tokens(&self) -> Vec<TokenId>;1253 fn collection_tokens(&self) -> Vec<TokenId>;pallets/fungible/src/lib.rsdiffbeforeafterboth25 budget::Budget,25 budget::Budget,26};26};27use pallet_common::{27use pallet_common::{28 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, CollectionHandle,28 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon,29 dispatch::CollectionDispatch, eth::collection_id_to_address,29 eth::collection_id_to_address,30};30};31use pallet_evm::Pallet as PalletEvm;31use pallet_evm::Pallet as PalletEvm;32use pallet_structure::Pallet as PalletStructure;32use pallet_structure::Pallet as PalletStructure;176176177 if balance == 0 {177 if balance == 0 {178 <Balance<T>>::remove((collection.id, owner));178 <Balance<T>>::remove((collection.id, owner));179 <PalletStructure<T>>::unnest_if_nested(180 owner,181 collection.id,182 TokenId::default()183 );179 } else {184 } else {180 <Balance<T>>::insert((collection.id, owner), balance);185 <Balance<T>>::insert((collection.id, owner), balance);181 }186 }229 None234 None230 };235 };231236232 if let Some(target) = T::CrossTokenAddressMapping::address_to_token(to) {237 // =========233 let handle = <CollectionHandle<T>>::try_get(target.0)?;234 let dispatch = T::CollectionDispatch::dispatch(handle);235 let dispatch = dispatch.as_dyn();236238237 dispatch.check_nesting(239 <PalletStructure<T>>::try_nest_if_sent_to_token(238 from.clone(),240 from.clone(),241 to,239 (collection.id, TokenId::default()),242 collection.id,240 target.1,243 TokenId::default(),241 nesting_budget,244 nesting_budget242 )?;245 )?;243 }244245 // =========246246247 if let Some(balance_to) = balance_to {247 if let Some(balance_to) = balance_to {248 // from != to248 // from != to306 }306 }307307308 for (to, _) in balances.iter() {308 for (to, _) in balances.iter() {309 if let Some(target) = T::CrossTokenAddressMapping::address_to_token(to) {310 let handle = <CollectionHandle<T>>::try_get(target.0)?;311 let dispatch = T::CollectionDispatch::dispatch(handle);312 let dispatch = dispatch.as_dyn();313314 dispatch.check_nesting(309 <PalletStructure<T>>::check_nesting(315 sender.clone(),310 sender.clone(),311 to,316 (collection.id, TokenId::default()),312 collection.id,317 target.1,313 TokenId::default(),318 nesting_budget,314 nesting_budget,319 )?;315 )?;320 }321 }316 }322317323 // =========318 // =========324319325 <TotalSupply<T>>::insert(collection.id, total_supply);320 <TotalSupply<T>>::insert(collection.id, total_supply);326 for (user, amount) in balances {321 for (user, amount) in balances {327 <Balance<T>>::insert((collection.id, &user), amount);322 <Balance<T>>::insert((collection.id, &user), amount);328323 <PalletStructure<T>>::nest_if_sent_to_token(&user, collection.id, TokenId::default());329 <PalletEvm<T>>::deposit_log(324 <PalletEvm<T>>::deposit_log(330 ERC20Events::Transfer {325 ERC20Events::Transfer {331 from: H160::default(),326 from: H160::default(),pallets/nonfungible/src/common.rsdiffbeforeafterboth353 <Pallet<T>>::check_nesting(self, sender, from, under, budget)353 <Pallet<T>>::check_nesting(self, sender, from, under, budget)354 }354 }355356 fn nest(357 &self,358 under: TokenId,359 to_nest: (CollectionId, TokenId)360 ) {361 <Pallet<T>>::nest((self.id, under), to_nest);362 }363364 fn unnest(365 &self,366 under: TokenId,367 to_unnest: (CollectionId, TokenId)368 ) {369 <Pallet<T>>::unnest((self.id, under), to_unnest);370 }355371356 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {372 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {357 <Owned<T>>::iter_prefix((self.id, account))373 <Owned<T>>::iter_prefix((self.id, account))pallets/nonfungible/src/lib.rsdiffbeforeafterboth27use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};27use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};28use pallet_common::{28use pallet_common::{29 Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, CollectionHandle,29 Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, CollectionHandle,30 dispatch::CollectionDispatch, eth::collection_id_to_address,30 eth::collection_id_to_address,31};31};32use pallet_structure::Pallet as PalletStructure;32use pallet_structure::Pallet as PalletStructure;33use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};33use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};77 NotNonfungibleDataUsedToMintFungibleCollectionToken,77 NotNonfungibleDataUsedToMintFungibleCollectionToken,78 /// Used amount > 1 with NFT78 /// Used amount > 1 with NFT79 NonfungibleItemsHaveNoAmount,79 NonfungibleItemsHaveNoAmount,80 /// Unable to burn NFT with children81 CantBurnNftWithChildren,80 }82 }818382 #[pallet::config]84 #[pallet::config]128 QueryKind = ValueQuery,130 QueryKind = ValueQuery,129 >;131 >;132133 /// Used to enumerate token's children134 #[pallet::storage]135 #[pallet::getter(fn token_children)]136 pub type TokenChildren<T: Config> = StorageNMap<137 Key = (138 Key<Twox64Concat, CollectionId>,139 Key<Twox64Concat, TokenId>,140 Key<Twox64Concat, (CollectionId, TokenId)>,141 ),142 Value = bool,143 QueryKind = ValueQuery,144 >;130145131 #[pallet::storage]146 #[pallet::storage]132 pub type AccountBalance<T: Config> = StorageNMap<147 pub type AccountBalance<T: Config> = StorageNMap<283 PalletCommon::destroy_collection(collection.0, sender)?;298 PalletCommon::destroy_collection(collection.0, sender)?;284299285 <TokenData<T>>::remove_prefix((id,), None);300 <TokenData<T>>::remove_prefix((id,), None);301 <TokenChildren<T>>::remove_prefix((id,), None);286 <Owned<T>>::remove_prefix((id,), None);302 <Owned<T>>::remove_prefix((id,), None);287 <TokensMinted<T>>::remove(id);303 <TokensMinted<T>>::remove(id);288 <TokensBurnt<T>>::remove(id);304 <TokensBurnt<T>>::remove(id);308 collection.check_allowlist(sender)?;324 collection.check_allowlist(sender)?;309 }325 }326327 if Self::token_has_children(collection.id, token) {328 return Err(<Error<T>>::CantBurnNftWithChildren.into());329 }310330311 let burnt = <TokensBurnt<T>>::get(collection.id)331 let burnt = <TokensBurnt<T>>::get(collection.id)312 .checked_add(1)332 .checked_add(1)322 <AccountBalance<T>>::insert((collection.id, token_data.owner.clone()), balance);342 <AccountBalance<T>>::insert((collection.id, token_data.owner.clone()), balance);323 }343 }344345 if let Some(owner) = T::CrossTokenAddressMapping::address_to_token(&token_data.owner) {346 Self::unnest(owner, (collection.id, token));347 }348324 // =========349 // =========325350554 None579 None555 };580 };556557 if let Some(target) = T::CrossTokenAddressMapping::address_to_token(to) {558 let handle = <CollectionHandle<T>>::try_get(target.0)?;559 let dispatch = T::CollectionDispatch::dispatch(handle);560 let dispatch = dispatch.as_dyn();561581562 dispatch.check_nesting(582 <PalletStructure<T>>::try_nest_if_sent_to_token(563 from.clone(),583 from.clone(),584 to,564 (collection.id, token),585 collection.id,565 target.1,586 token,566 nesting_budget,587 nesting_budget567 )?;588 )?;568 }569589570 // =========590 // =========571591654674655 for (i, data) in data.iter().enumerate() {675 for (i, data) in data.iter().enumerate() {656 let token = TokenId(first_token + i as u32 + 1);676 let token = TokenId(first_token + i as u32 + 1);657 if let Some(target) = T::CrossTokenAddressMapping::address_to_token(&data.owner) {677658 let handle = <CollectionHandle<T>>::try_get(target.0)?;659 let dispatch = T::CollectionDispatch::dispatch(handle);660 let dispatch = dispatch.as_dyn();661 dispatch.check_nesting(678 <PalletStructure<T>>::check_nesting(662 sender.clone(),679 sender.clone(),680 &data.owner,663 (collection.id, token),681 collection.id,664 target.1,682 token,665 nesting_budget,683 nesting_budget,666 )?;684 )?;667 }668 }685 }669686670 // =========687 // =========681 },698 },682 );699 );700701 <PalletStructure<T>>::nest_if_sent_to_token(&data.owner, collection.id, TokenId(token));683702684 if let Err(e) = Self::set_token_properties(703 if let Err(e) = Self::set_token_properties(685 collection,704 collection,928 Ok(())947 Ok(())929 }948 }949950 fn nest(951 under: (CollectionId, TokenId),952 to_nest: (CollectionId, TokenId),953 ) {954 <TokenChildren<T>>::insert(955 (under.0, under.1, (to_nest.0, to_nest.1)),956 true957 );958 }959960 fn unnest(961 under: (CollectionId, TokenId),962 to_unnest: (CollectionId, TokenId),963 ) {964 <TokenChildren<T>>::remove(965 (under.0, under.1, to_unnest)966 );967 }968969 fn token_has_children(collection_id: CollectionId, token_id: TokenId) -> bool {970 <TokenChildren<T>>::iter_prefix((collection_id, token_id)).next().is_some()971 }930972931 /// Delegated to `create_multiple_items`973 /// Delegated to `create_multiple_items`932 pub fn create_item(974 pub fn create_item(pallets/refungible/src/lib.rsdiffbeforeafterboth23};23};24use pallet_evm::account::CrossAccountId;24use pallet_evm::account::CrossAccountId;25use pallet_common::{25use pallet_common::{26 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, CollectionHandle,26 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon,27 dispatch::CollectionDispatch,28};27};29use pallet_structure::Pallet as PalletStructure;28use pallet_structure::Pallet as PalletStructure;30use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};29use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};265 // =========264 // =========266265267 <Owned<T>>::remove((collection.id, owner, token));266 <Owned<T>>::remove((collection.id, owner, token));267 <PalletStructure<T>>::unnest_if_nested(owner, collection.id, token);268 <AccountBalance<T>>::insert((collection.id, owner), account_balance);268 <AccountBalance<T>>::insert((collection.id, owner), account_balance);269 Self::burn_token(collection, token)?;269 Self::burn_token(collection, token)?;270 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(270 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(292292293 if balance == 0 {293 if balance == 0 {294 <Owned<T>>::remove((collection.id, owner, token));294 <Owned<T>>::remove((collection.id, owner, token));295 <PalletStructure<T>>::unnest_if_nested(owner, collection.id, token);295 <Balance<T>>::remove((collection.id, token, owner));296 <Balance<T>>::remove((collection.id, token, owner));296 <AccountBalance<T>>::insert((collection.id, owner), account_balance);297 <AccountBalance<T>>::insert((collection.id, owner), account_balance);297 } else {298 } else {372 None373 None373 };374 };374375375 if let Some(target) = T::CrossTokenAddressMapping::address_to_token(to) {376 // =========376 let handle = <CollectionHandle<T>>::try_get(target.0)?;377 let dispatch = T::CollectionDispatch::dispatch(handle);378 let dispatch = dispatch.as_dyn();379377380 dispatch.check_nesting(378 <PalletStructure<T>>::try_nest_if_sent_to_token(381 from.clone(),379 from.clone(),380 to,382 (collection.id, token),381 collection.id,383 target.1,382 token,384 nesting_budget,383 nesting_budget385 )?;384 )?;386 }387388 // =========389385390 if let Some(balance_to) = balance_to {386 if let Some(balance_to) = balance_to {391 // from != to387 // from != to488 for (i, token) in data.iter().enumerate() {484 for (i, token) in data.iter().enumerate() {489 let token_id = TokenId(first_token_id + i as u32 + 1);485 let token_id = TokenId(first_token_id + i as u32 + 1);490 for (to, _) in token.users.iter() {486 for (to, _) in token.users.iter() {491 if let Some(target) = T::CrossTokenAddressMapping::address_to_token(to) {492 let handle = <CollectionHandle<T>>::try_get(target.0)?;493 let dispatch = T::CollectionDispatch::dispatch(handle);494 let dispatch = dispatch.as_dyn();495487496 dispatch.check_nesting(488 <PalletStructure<T>>::check_nesting(497 sender.clone(),489 sender.clone(),490 to,498 (collection.id, token_id),491 collection.id,499 target.1,492 token_id,500 nesting_budget,493 nesting_budget,501 )?;494 )?;502 }503 }495 }504 }496 }505497525 }518 }526 <Balance<T>>::insert((collection.id, token_id, &user), amount);519 <Balance<T>>::insert((collection.id, token_id, &user), amount);527 <Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);520 <Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);521 <PalletStructure<T>>::nest_if_sent_to_token(&user, collection.id, TokenId(token_id));522528 // TODO: ERC20 transfer event523 // TODO: ERC20 transfer event529 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(524 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(pallets/structure/src/lib.rsdiffbeforeafterboth1#![cfg_attr(not(feature = "std"), no_std)]1#![cfg_attr(not(feature = "std"), no_std)]223use pallet_common::CommonCollectionOperations;3use sp_std::collections::btree_set::BTreeSet;4use sp_std::collections::btree_set::BTreeSet;455use frame_support::dispatch::DispatchError;6use frame_support::dispatch::{DispatchError, DispatchResult};6use frame_support::fail;7use frame_support::fail;7pub use pallet::*;8pub use pallet::*;8use pallet_common::{dispatch::CollectionDispatch, CollectionHandle};9use pallet_common::{dispatch::CollectionDispatch, CollectionHandle};174 v if v == target_parent => return Ok(true),175 v if v == target_parent => return Ok(true),175 // Token is owned by other user176 // Token is owned by other user176 Parent::User(_) => return Ok(false),177 Parent::User(_) => return Ok(false),177 Parent::TokenNotFound => return Ok(false),178 Parent::TokenNotFound => return Err(<Error<T>>::TokenNotFound.into()),178 // Continue parent chain179 // Continue parent chain179 Parent::Token(_, _) => {}180 Parent::Token(_, _) => {}180 }181 }183 Err(<Error<T>>::DepthLimit.into())184 Err(<Error<T>>::DepthLimit.into())184 }185 }186187 pub fn check_nesting(188 from: T::CrossAccountId,189 under: &T::CrossAccountId,190 collection_id: CollectionId,191 token_id: TokenId,192 nesting_budget: &dyn Budget193 ) -> DispatchResult {194 Self::try_dispatched(195 under,196 |d, parent_id| d.check_nesting(197 from,198 (collection_id, token_id),199 parent_id,200 nesting_budget201 )202 )203 }204205 pub fn try_nest_if_sent_to_token(206 from: T::CrossAccountId,207 under: &T::CrossAccountId,208 collection_id: CollectionId,209 token_id: TokenId,210 nesting_budget: &dyn Budget211 ) -> DispatchResult {212 Self::try_dispatched(213 under,214 |d, parent_id| {215 d.check_nesting(216 from,217 (collection_id, token_id),218 parent_id,219 nesting_budget220 )?;221222 d.nest(parent_id, (collection_id, token_id));223224 Ok(())225 }226 )227 }228229 pub fn nest_if_sent_to_token(230 owner: &T::CrossAccountId,231 collection_id: CollectionId,232 token_id: TokenId233 ) {234 Self::dispatched(235 owner,236 |d, parent_id| d.nest(237 parent_id,238 (collection_id, token_id)239 )240 );241 }242243 pub fn unnest_if_nested(244 owner: &T::CrossAccountId,245 collection_id: CollectionId,246 token_id: TokenId247 ) {248 Self::dispatched(249 owner,250 |d, parent_id| d.unnest(251 parent_id,252 (collection_id, token_id)253 )254 );255 }256257 fn dispatched(258 account: &T::CrossAccountId,259 action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId)260 ) {261 Self::try_dispatched(262 account,263 |d, id| {264 action(d, id);265 Ok(())266 }267 ).unwrap();268 }269270 fn try_dispatched(271 account: &T::CrossAccountId,272 action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId) -> DispatchResult273 ) -> DispatchResult {274 let account = T::CrossTokenAddressMapping::address_to_token(account);275276 if account.is_none() {277 return Ok(());278 }279280 let account = account.unwrap();281282 let handle = <CollectionHandle<T>>::try_get(account.0);283284 if handle.is_err() {285 return Ok(());286 }287288 let handle = handle.unwrap();289290 let dispatch = T::CollectionDispatch::dispatch(handle);291 let dispatch = dispatch.as_dyn();292293 action(dispatch, account.1)294 }185}295}186296