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

difftreelog

feat add token children

Daniel Shiposha2022-05-26parent: #459d9af.patch.diff
in: master

6 files changed

modifiedpallets/common/src/lib.rsdiffbeforeafterboth
1237 budget: &dyn Budget,1237 budget: &dyn Budget,
1238 ) -> DispatchResult;1238 ) -> DispatchResult;
1239
1240 fn nest(
1241 &self,
1242 _under: TokenId,
1243 _to_nest: (CollectionId, TokenId)
1244 ) {}
1245
1246 fn unnest(
1247 &self,
1248 _under: TokenId,
1249 _to_nest: (CollectionId, TokenId)
1250 ) {}
12391251
1240 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>;
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
25 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;
176176
177 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 None
230 };235 };
231236
232 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();
236238
237 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_budget
242 )?;245 )?;
243 }
244
245 // =========
246246
247 if let Some(balance_to) = balance_to {247 if let Some(balance_to) = balance_to {
248 // from != to248 // from != to
306 }306 }
307307
308 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();
313
314 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 }
322317
323 // =========318 // =========
324319
325 <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(),
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
353 <Pallet<T>>::check_nesting(self, sender, from, under, budget)353 <Pallet<T>>::check_nesting(self, sender, from, under, budget)
354 }354 }
355
356 fn nest(
357 &self,
358 under: TokenId,
359 to_nest: (CollectionId, TokenId)
360 ) {
361 <Pallet<T>>::nest((self.id, under), to_nest);
362 }
363
364 fn unnest(
365 &self,
366 under: TokenId,
367 to_unnest: (CollectionId, TokenId)
368 ) {
369 <Pallet<T>>::unnest((self.id, under), to_unnest);
370 }
355371
356 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))
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
27use 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 NFT
79 NonfungibleItemsHaveNoAmount,79 NonfungibleItemsHaveNoAmount,
80 /// Unable to burn NFT with children
81 CantBurnNftWithChildren,
80 }82 }
8183
82 #[pallet::config]84 #[pallet::config]
128 QueryKind = ValueQuery,130 QueryKind = ValueQuery,
129 >;131 >;
132
133 /// Used to enumerate token's children
134 #[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 >;
130145
131 #[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)?;
284299
285 <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 }
326
327 if Self::token_has_children(collection.id, token) {
328 return Err(<Error<T>>::CantBurnNftWithChildren.into());
329 }
310330
311 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 }
344
345 if let Some(owner) = T::CrossTokenAddressMapping::address_to_token(&token_data.owner) {
346 Self::unnest(owner, (collection.id, token));
347 }
348
324 // =========349 // =========
325350
554 None579 None
555 };580 };
556
557 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();
561581
562 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_budget
567 )?;588 )?;
568 }
569589
570 // =========590 // =========
571591
654674
655 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) {677
658 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 }
669686
670 // =========687 // =========
681 },698 },
682 );699 );
700
701 <PalletStructure<T>>::nest_if_sent_to_token(&data.owner, collection.id, TokenId(token));
683702
684 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 }
949
950 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 true
957 );
958 }
959
960 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 }
968
969 fn token_has_children(collection_id: CollectionId, token_id: TokenId) -> bool {
970 <TokenChildren<T>>::iter_prefix((collection_id, token_id)).next().is_some()
971 }
930972
931 /// Delegated to `create_multiple_items`973 /// Delegated to `create_multiple_items`
932 pub fn create_item(974 pub fn create_item(
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
23};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 // =========
266265
267 <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(
292292
293 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 None
373 };374 };
374375
375 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();
379377
380 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_budget
385 )?;384 )?;
386 }
387
388 // =========
389385
390 if let Some(balance_to) = balance_to {386 if let Some(balance_to) = balance_to {
391 // from != to387 // from != to
488 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();
495487
496 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 }
505497
525 }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));
522
528 // TODO: ERC20 transfer event523 // TODO: ERC20 transfer event
529 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(524 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(
modifiedpallets/structure/src/lib.rsdiffbeforeafterboth
1#![cfg_attr(not(feature = "std"), no_std)]1#![cfg_attr(not(feature = "std"), no_std)]
22
3use pallet_common::CommonCollectionOperations;
3use sp_std::collections::btree_set::BTreeSet;4use sp_std::collections::btree_set::BTreeSet;
45
5use 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 user
176 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 chain
179 Parent::Token(_, _) => {}180 Parent::Token(_, _) => {}
180 }181 }
183 Err(<Error<T>>::DepthLimit.into())184 Err(<Error<T>>::DepthLimit.into())
184 }185 }
186
187 pub fn check_nesting(
188 from: T::CrossAccountId,
189 under: &T::CrossAccountId,
190 collection_id: CollectionId,
191 token_id: TokenId,
192 nesting_budget: &dyn Budget
193 ) -> 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_budget
201 )
202 )
203 }
204
205 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 Budget
211 ) -> 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_budget
220 )?;
221
222 d.nest(parent_id, (collection_id, token_id));
223
224 Ok(())
225 }
226 )
227 }
228
229 pub fn nest_if_sent_to_token(
230 owner: &T::CrossAccountId,
231 collection_id: CollectionId,
232 token_id: TokenId
233 ) {
234 Self::dispatched(
235 owner,
236 |d, parent_id| d.nest(
237 parent_id,
238 (collection_id, token_id)
239 )
240 );
241 }
242
243 pub fn unnest_if_nested(
244 owner: &T::CrossAccountId,
245 collection_id: CollectionId,
246 token_id: TokenId
247 ) {
248 Self::dispatched(
249 owner,
250 |d, parent_id| d.unnest(
251 parent_id,
252 (collection_id, token_id)
253 )
254 );
255 }
256
257 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 }
269
270 fn try_dispatched(
271 account: &T::CrossAccountId,
272 action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId) -> DispatchResult
273 ) -> DispatchResult {
274 let account = T::CrossTokenAddressMapping::address_to_token(account);
275
276 if account.is_none() {
277 return Ok(());
278 }
279
280 let account = account.unwrap();
281
282 let handle = <CollectionHandle<T>>::try_get(account.0);
283
284 if handle.is_err() {
285 return Ok(());
286 }
287
288 let handle = handle.unwrap();
289
290 let dispatch = T::CollectionDispatch::dispatch(handle);
291 let dispatch = dispatch.as_dyn();
292
293 action(dispatch, account.1)
294 }
185}295}
186296