git.delta.rocks / unique-network / refs/commits / 5bde44b9e4f5

difftreelog

feat draft xcm deposit_asset

Daniel Shiposha2023-10-17parent: #c652c1e.patch.diff
in: master

8 files changed

modifiedpallets/balances-adapter/src/common.rsdiffbeforeafterboth
33
4use frame_support::{ensure, fail, weights::Weight};4use frame_support::{
5 ensure, fail,
6 traits::tokens::{fungible::Mutate, Fortitude, Precision},
7 weights::Weight,
8};
5use pallet_balances::{weights::SubstrateWeight as BalancesWeight, WeightInfo};9use pallet_balances::{weights::SubstrateWeight as BalancesWeight, WeightInfo};
6use pallet_common::{CommonCollectionOperations, CommonWeightInfo, Error as CommonError};10use pallet_common::{
11 erc::CrossAccountId, CommonCollectionOperations, CommonWeightInfo, Error as CommonError,
12};
7use up_data_structs::TokenId;13use up_data_structs::{budget::Budget, TokenId};
814
9use crate::{Config, NativeFungibleHandle, Pallet};15use crate::{Config, NativeFungibleHandle, Pallet};
1016
332 0338 0
333 }339 }
340
341 fn xcm_extensions(&self) -> Option<&dyn pallet_common::XcmExtensions<T>> {
342 Some(self)
343 }
334344
335 fn set_allowance_for_all(345 fn set_allowance_for_all(
336 &self,346 &self,
357 }367 }
358}368}
369
370impl<T: Config> pallet_common::XcmExtensions<T> for NativeFungibleHandle<T> {
371 fn is_foreign(&self) -> bool {
372 false
373 }
374
375 fn create_item_internal(
376 &self,
377 _depositor: &<T>::CrossAccountId,
378 to: <T>::CrossAccountId,
379 data: up_data_structs::CreateItemData,
380 _nesting_budget: &dyn Budget,
381 ) -> Result<TokenId, sp_runtime::DispatchError> {
382 match &data {
383 up_data_structs::CreateItemData::Fungible(fungible_data) => {
384 T::Mutate::mint_into(
385 to.as_sub(),
386 fungible_data
387 .value
388 .try_into()
389 .map_err(|_| sp_runtime::ArithmeticError::Overflow)?,
390 )?;
391
392 Ok(TokenId::default())
393 }
394 _ => {
395 fail!(<CommonError<T>>::NotFungibleDataUsedToMintFungibleCollectionToken)
396 }
397 }
398 }
399
400 fn transfer_item_internal(
401 &self,
402 _depositor: &<T>::CrossAccountId,
403 from: &<T>::CrossAccountId,
404 to: &<T>::CrossAccountId,
405 token: TokenId,
406 amount: u128,
407 _nesting_budget: &dyn Budget,
408 ) -> sp_runtime::DispatchResult {
409 ensure!(
410 token == TokenId::default(),
411 <CommonError<T>>::FungibleItemsHaveNoId
412 );
413
414 <Pallet<T>>::transfer(from, to, amount)
415 .map(|_| ())
416 .map_err(|post_info| post_info.error)
417 }
418
419 fn burn_item_internal(
420 &self,
421 from: T::CrossAccountId,
422 token: TokenId,
423 amount: u128,
424 ) -> sp_runtime::DispatchResult {
425 ensure!(
426 token == TokenId::default(),
427 <CommonError<T>>::FungibleItemsHaveNoId
428 );
429
430 T::Mutate::burn_from(
431 from.as_sub(),
432 amount
433 .try_into()
434 .map_err(|_| sp_runtime::ArithmeticError::Overflow)?,
435 Precision::Exact,
436 Fortitude::Polite,
437 )?;
438
439 Ok(())
440 }
441}
359442
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
80use sp_std::vec::Vec;80use sp_std::vec::Vec;
81use sp_weights::Weight;81use sp_weights::Weight;
82use up_data_structs::{82use up_data_structs::{
83 budget::Budget, AccessMode, Collection, CollectionId, CollectionLimits, CollectionMode,83 budget::Budget, mapping::TokenAddressMapping, AccessMode, Collection, CollectionId,
84 CollectionPermissions, CollectionProperties as CollectionPropertiesT, CollectionStats,84 CollectionLimits, CollectionMode, CollectionPermissions,
85 CreateCollectionData, CreateItemData, CreateItemExData, PhantomType, PropertiesError,85 CollectionProperties as CollectionPropertiesT, CollectionStats, CreateCollectionData,
86 PropertiesPermissionMap, Property, PropertyKey, PropertyKeyPermission, PropertyPermission,86 CreateItemData, CreateItemExData, PhantomType, PropertiesError, PropertiesPermissionMap,
787 /// Fungible tokens hold no ID, and the default value of TokenId for a fungible collection is 0.788 /// Fungible tokens hold no ID, and the default value of TokenId for a fungible collection is 0.
788 FungibleItemsHaveNoId,789 FungibleItemsHaveNoId,
790
791 /// Not Fungible item data used to mint in Fungible collection.
792 NotFungibleDataUsedToMintFungibleCollectionToken,
789 }793 }
790794
791 /// Storage of the count of created collections. Essentially contains the last collection ID.795 /// Storage of the count of created collections. Essentially contains the last collection ID.
2347 /// Is the collection a foreign one?2351 /// Is the collection a foreign one?
2348 fn is_foreign(&self) -> bool;2352 fn is_foreign(&self) -> bool;
23492353
2350 /// Create a collection's item.2354 /// Create a collection's item using a transaction.
2355 ///
2356 /// This function performs additional XCM-related checks before the actual creation.
2357 #[transactional]
2351 fn create_item(2358 fn create_item(
2352 &self,2359 &self,
2360 depositor: &T::CrossAccountId,
2353 to: T::CrossAccountId,2361 to: T::CrossAccountId,
2354 data: CreateItemData,2362 data: CreateItemData,
2363 nesting_budget: &dyn Budget,
2355 ) -> Result<TokenId, DispatchError>;2364 ) -> Result<TokenId, DispatchError> {
2365 if T::CrossTokenAddressMapping::is_token_address(&to) {
2366 return unsupported!(T);
2367 }
2368
2369 self.create_item_internal(depositor, to, data, nesting_budget)
2370 }
2371
2372 /// Create a collection's item.
2373 fn create_item_internal(
2374 &self,
2375 depositor: &T::CrossAccountId,
2376 to: T::CrossAccountId,
2377 data: CreateItemData,
2378 nesting_budget: &dyn Budget,
2379 ) -> Result<TokenId, DispatchError>;
2380
2381 /// Transfer an item from the `from` account to the `to` account using a transaction.
2382 ///
2383 /// This function performs additional XCM-related checks before the actual transfer.
2384 #[transactional]
2385 fn transfer_item(
2386 &self,
2387 depositor: &T::CrossAccountId,
2388 from: &T::CrossAccountId,
2389 to: &T::CrossAccountId,
2390 token: TokenId,
2391 amount: u128,
2392 nesting_budget: &dyn Budget,
2393 ) -> DispatchResult {
2394 if T::CrossTokenAddressMapping::is_token_address(&to) {
2395 return unsupported!(T);
2396 }
2397
2398 self.transfer_item_internal(depositor, from, to, token, amount, nesting_budget)
2399 }
23562400
2357 /// Transfer an item from the `from` account to the `to` account.2401 /// Transfer an item from the `from` account to the `to` account.
2358 fn transfer(2402 fn transfer_item_internal(
2359 &self,2403 &self,
2404 depositor: &T::CrossAccountId,
2360 from: T::CrossAccountId,2405 from: &T::CrossAccountId,
2361 to: T::CrossAccountId,2406 to: &T::CrossAccountId,
2362 token: TokenId,2407 token: TokenId,
2363 amount: u128,2408 amount: u128,
2409 nesting_budget: &dyn Budget,
2364 ) -> DispatchResult;2410 ) -> DispatchResult;
2411
2412 /// Burn a collection's item using a transaction.
2413 #[transactional]
2414 fn burn_item(&self, from: T::CrossAccountId, token: TokenId, amount: u128) -> DispatchResult {
2415 self.burn_item_internal(from, token, amount)
2416 }
23652417
2366 /// Burn a collection's item.2418 /// Burn a collection's item.
2367 fn burn(&self, from: T::CrossAccountId, token: TokenId, amount: u128) -> DispatchResult;2419 fn burn_item_internal(
2420 &self,
2421 from: T::CrossAccountId,
2422 token: TokenId,
modifiedpallets/foreign-assets/src/lib.rsdiffbeforeafterboth
20//! - [`Call`]20//! - [`Call`]
21//! - [`Pallet`]21//! - [`Pallet`]
22//!22//!
23//! ## Overview
24//!
25//! The foreign assests pallet provides functions for:
26//!
27//! - Local and foreign assets management. The foreign assets can be updated without runtime upgrade.
28//! - Bounds between asset and target collection for cross chain transfer and inner transfers.
29//!
30//! ## Overview23//! ## Overview
31//!24//!
32//! Under construction25//! Under construction
37use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::EnsureOrigin, PalletId};30use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::EnsureOrigin, PalletId};
38use frame_system::pallet_prelude::*;31use frame_system::pallet_prelude::*;
39use pallet_common::{32use pallet_common::{
40 dispatch::CollectionDispatch, erc::CrossAccountId, NATIVE_FUNGIBLE_COLLECTION_ID,33 dispatch::CollectionDispatch, erc::CrossAccountId, XcmExtensions, NATIVE_FUNGIBLE_COLLECTION_ID,
41};34};
42use sp_runtime::traits::AccountIdConversion;35use sp_runtime::traits::AccountIdConversion;
43use sp_std::{vec, vec::Vec};36use sp_std::{vec, vec::Vec};
44// NOTE: MultiLocation is used in storages, we will need to do migration if upgrade the
45// MultiLocation to the XCM v3.
46use staging_xcm::{37use staging_xcm::{
47 opaque::latest::{prelude::XcmError, Weight},38 opaque::latest::{prelude::XcmError, Weight},
48 v3::{prelude::*, MultiAsset, XcmContext},39 v3::{prelude::*, MultiAsset, XcmContext},
49};40};
50use staging_xcm_executor::{41use staging_xcm_executor::{
51 traits::{TransactAsset, WeightTrader},42 traits::{ConvertLocation, Error as XcmExecutorError, TransactAsset, WeightTrader},
52 Assets,43 Assets,
53};44};
54use up_data_structs::{45use up_data_structs::{
55 CollectionId, CollectionMode, CollectionName, CreateCollectionData, PropertyKey, TokenId,46 budget::ZeroBudget, CollectionId, CollectionMode, CollectionName, CreateCollectionData,
47 CreateFungibleData, CreateItemData, CreateNftData, Property, PropertyKey, TokenId,
56};48};
5749
58pub mod weights;50pub mod weights;
87 /// The ID of the foreign assets pallet.79 /// The ID of the foreign assets pallet.
88 type PalletId: Get<PalletId>;80 type PalletId: Get<PalletId>;
81
82 /// Self-location of this parachain.
83 type SelfLocation: Get<MultiLocation>;
84
85 /// The converter from a MultiLocation to a CrossAccountId.
86 type LocationToAccountId: ConvertLocation<Self::CrossAccountId>;
8987
90 /// Weight information for the extrinsics in this module.88 /// Weight information for the extrinsics in this module.
91 type WeightInfo: WeightInfo;89 type WeightInfo: WeightInfo;
113 pub type ForeignReserveLocationToCollection<T: Config> =111 pub type ForeignReserveLocationToCollection<T: Config> =
114 StorageMap<_, Twox64Concat, staging_xcm::v3::MultiLocation, CollectionId, OptionQuery>;112 StorageMap<_, Twox64Concat, staging_xcm::v3::MultiLocation, CollectionId, OptionQuery>;
113
114 /// The corresponding reserve location of collections.
115 #[pallet::storage]
116 #[pallet::getter(fn collection_to_foreign_reserve_location)]
117 pub type CollectionToForeignReserveLocation<T: Config> =
118 StorageMap<_, Twox64Concat, CollectionId, staging_xcm::v3::MultiLocation, OptionQuery>;
115119
116 /// The correponding NFT token id of reserve NFTs120 /// The correponding NFT token id of reserve NFTs
117 #[pallet::storage]121 #[pallet::storage]
180 )?;184 )?;
181185
182 <ForeignReserveLocationToCollection<T>>::insert(reserve_location, collection_id);186 <ForeignReserveLocationToCollection<T>>::insert(reserve_location, collection_id);
187 <CollectionToForeignReserveLocation<T>>::insert(collection_id, reserve_location);
183188
184 Self::deposit_event(Event::<T>::ForeignAssetRegistered {189 Self::deposit_event(Event::<T>::ForeignAssetRegistered {
185 asset_id: collection_id,190 asset_id: collection_id,
211 .expect("key length < max property key length; qed")216 .expect("key length < max property key length; qed")
212 }217 }
218
219 fn native_asset_location_to_collection(
220 asset_location: &MultiLocation,
221 ) -> Result<Option<CollectionId>, XcmError> {
222 let self_location = T::SelfLocation::get();
223
224 if *asset_location == Here.into() {
225 Ok(Some(NATIVE_FUNGIBLE_COLLECTION_ID))
226 } else if *asset_location == self_location {
227 Ok(Some(NATIVE_FUNGIBLE_COLLECTION_ID))
228 } else if asset_location.parents == self_location.parents {
229 match asset_location
230 .interior
231 .match_and_split(&self_location.interior)
232 {
233 Some(GeneralIndex(collection_id)) => Ok(Some(CollectionId(
234 (*collection_id)
235 .try_into()
236 .map_err(|_| XcmExecutorError::AssetIdConversionFailed)?,
237 ))),
238 _ => Ok(None),
239 }
240 } else {
241 Ok(None)
242 }
243 }
244
245 fn multiasset_to_collection(asset: &MultiAsset) -> Result<CollectionId, XcmError> {
246 let AssetId::Concrete(asset_reserve_location) = asset.id else {
247 return Err(XcmExecutorError::AssetNotHandled.into());
248 };
249
250 Self::native_asset_location_to_collection(&asset_reserve_location)?
251 .or_else(|| Self::foreign_reserve_location_to_collection(asset_reserve_location))
252 .ok_or_else(|| XcmExecutorError::AssetIdConversionFailed.into())
253 }
254
255 fn native_asset_instance_to_token_id(
256 asset_instance: &AssetInstance,
257 ) -> Result<TokenId, XcmError> {
258 match asset_instance {
259 AssetInstance::Index(token_id) => Ok(TokenId(
260 (*token_id)
261 .try_into()
262 .map_err(|_| XcmError::AssetNotFound)?,
263 )),
264 _ => Err(XcmError::AssetNotFound),
265 }
266 }
267
268 /// Obtains the token id of the `asset_instance` in the collection.
269 ///
270 /// Returns `Ok(None)` only if the `asset_instance` points to a foreign item
271 /// and it haven't been created on this blockchain yet.
272 ///
273 /// If the `asset_instance` points to a native item, it cannot return `Ok(None)`.
274 fn asset_instance_to_token_id(
275 xcm_ext: &dyn XcmExtensions<T>,
276 collection_id: CollectionId,
277 asset_instance: &AssetInstance,
278 ) -> Result<Option<TokenId>, XcmError> {
279 if xcm_ext.is_foreign() {
280 Ok(Self::foreign_reserve_asset_instance_to_token_id(
281 collection_id,
282 asset_instance,
283 ))
284 } else {
285 Self::native_asset_instance_to_token_id(asset_instance).map(Some)
286 }
287 }
288
289 fn create_foreign_asset_instance(
290 xcm_ext: &dyn XcmExtensions<T>,
291 collection_id: CollectionId,
292 asset_instance: &AssetInstance,
293 to: T::CrossAccountId,
294 ) -> XcmResult {
295 let asset_instance_encoded = asset_instance.encode();
296
297 let derivative_token_id = xcm_ext
298 .create_item(
299 &Self::pallet_account(),
300 to,
301 CreateItemData::NFT(CreateNftData {
302 properties: vec![Property {
303 key: Self::reserve_asset_instance_property_key(),
304 value: asset_instance_encoded
305 .try_into()
306 .expect("asset instance length <= 32 bytes which is less than value length limit; qed"),
307 }]
308 .try_into()
309 .expect("just one property can always be stored; qed"),
310 }),
311 &ZeroBudget,
312 )
313 .map_err(|_| XcmError::FailedToTransactAsset("non-fungible item deposit failed"))?;
314
315 <ForeignReserveAssetInstanceToTokenId<T>>::insert(
316 collection_id,
317 asset_instance,
318 derivative_token_id,
319 );
320
321 Ok(())
322 }
323
324 fn deposit_asset_instance(
325 xcm_ext: &dyn XcmExtensions<T>,
326 collection_id: CollectionId,
327 to: T::CrossAccountId,
328 asset_instance: &AssetInstance,
329 ) -> XcmResult {
330 if let Some(token_id) =
331 Self::asset_instance_to_token_id(xcm_ext, collection_id, asset_instance)?
332 {
333 let depositor = &Self::pallet_account();
334 let from = depositor;
335 let amount = 1;
336
337 xcm_ext
338 .transfer_item(depositor, from, &to, token_id, amount, &ZeroBudget)
339 .map_err(|_| XcmError::FailedToTransactAsset("non-fungible item deposit failed"))
340 } else {
341 Self::create_foreign_asset_instance(xcm_ext, collection_id, asset_instance, to)
342 }
343 }
213}344}
214345
215impl<T: Config> TransactAsset for Pallet<T> {346impl<T: Config> TransactAsset for Pallet<T> {
234 fn check_out(_dest: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {}365 fn check_out(_dest: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {}
235366
236 fn deposit_asset(what: &MultiAsset, to: &MultiLocation, context: &XcmContext) -> XcmResult {367 fn deposit_asset(what: &MultiAsset, to: &MultiLocation, context: &XcmContext) -> XcmResult {
368 let collection_id = Self::multiasset_to_collection(what)?;
369 let dispatch =
370 T::CollectionDispatch::dispatch(collection_id).map_err(|_| XcmError::AssetNotFound)?;
371
372 let collection = dispatch.as_dyn();
237 Err(XcmError::Unimplemented)373 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::Unimplemented)?;
374
375 let to = T::LocationToAccountId::convert_location(to)
376 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;
377
378 match what.fun {
379 Fungibility::Fungible(amount) => xcm_ext
380 .create_item(
381 &Self::pallet_account(),
382 to,
383 CreateItemData::Fungible(CreateFungibleData { value: amount }),
384 &ZeroBudget,
385 )
386 .map(|_| ())
387 .map_err(|_| XcmError::FailedToTransactAsset("fungible item deposit failed")),
388
389 Fungibility::NonFungible(asset_instance) => {
390 Self::deposit_asset_instance(xcm_ext, collection_id, to, &asset_instance)
391 }
392 }
238 }393 }
239394
240 fn withdraw_asset(395 fn withdraw_asset(
263 if collection_id == NATIVE_FUNGIBLE_COLLECTION_ID {418 if collection_id == NATIVE_FUNGIBLE_COLLECTION_ID {
264 Some(Here.into())419 Some(Here.into())
265 } else {420 } else {
266 // let dispatch = T::CollectionDispatch::dispatch(collection_id).ok()?;421 let dispatch = T::CollectionDispatch::dispatch(collection_id).ok()?;
267 // let collection = dispatch.as_dyn();
268 // let xcm_ext = collection.xcm_extensions()?;
269
270 // if xcm_ext.is_foreign() {
271 // let encoded_location =
272 // collection.property(&<Pallet<T>>::reserve_location_property_key())?;
273 // MultiLocation::decode(&mut &encoded_location[..]).ok()
274 // } else {
275 // T::SelfLocation::get()
276 // .pushed_with_interior(GeneralIndex(collection_id.0.into()))
277 // .ok()
278 // }
279 todo!()422 let collection = dispatch.as_dyn();
423 let xcm_ext = collection.xcm_extensions()?;
424
425 if xcm_ext.is_foreign() {
426 <Pallet<T>>::collection_to_foreign_reserve_location(collection_id)
427 } else {
428 T::SelfLocation::get()
429 .pushed_with_interior(GeneralIndex(collection_id.0.into()))
430 .ok()
431 }
280 }432 }
281 }433 }
282}434}
modifiedpallets/fungible/src/common.rsdiffbeforeafterboth
19use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};19use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};
20use pallet_common::{20use pallet_common::{
21 weights::WeightInfo as _, with_weight, CommonCollectionOperations, CommonWeightInfo,21 weights::WeightInfo as _, with_weight, CommonCollectionOperations, CommonWeightInfo,
22 Error as CommonError, RefungibleExtensions, SelfWeightOf as PalletCommonWeightOf,22 Error as CommonError, SelfWeightOf as PalletCommonWeightOf, XcmExtensions,
23};23};
24use sp_runtime::{ArithmeticError, DispatchError};24use sp_runtime::{ArithmeticError, DispatchError};
25use sp_std::{vec, vec::Vec};25use sp_std::{vec, vec::Vec};
114 <Pallet<T>>::create_item(self, &sender, (to, fungible_data.value), nesting_budget),114 <Pallet<T>>::create_item(self, &sender, (to, fungible_data.value), nesting_budget),
115 <CommonWeights<T>>::create_item(&data),115 <CommonWeights<T>>::create_item(&data),
116 ),116 ),
117 _ => fail!(<Error<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),117 _ => fail!(<CommonError<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),
118 }118 }
119 }119 }
120120
133 .checked_add(data.value)133 .checked_add(data.value)
134 .ok_or(ArithmeticError::Overflow)?;134 .ok_or(ArithmeticError::Overflow)?;
135 }135 }
136 _ => fail!(<Error<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),136 _ => fail!(<CommonError<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),
137 }137 }
138 }138 }
139139
152 let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);152 let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);
153 let data = match data {153 let data = match data {
154 up_data_structs::CreateItemExData::Fungible(f) => f,154 up_data_structs::CreateItemExData::Fungible(f) => f,
155 _ => fail!(<Error<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),155 _ => fail!(<CommonError<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),
156 };156 };
157157
158 with_weight(158 with_weight(
435 <TotalSupply<T>>::try_get(self.id).ok()435 <TotalSupply<T>>::try_get(self.id).ok()
436 }436 }
437
438 fn xcm_extensions(&self) -> Option<&dyn XcmExtensions<T>> {
439 Some(self)
440 }
437441
438 fn set_allowance_for_all(442 fn set_allowance_for_all(
439 &self,443 &self,
454 }458 }
455}459}
460
461impl<T: Config> XcmExtensions<T> for FungibleHandle<T> {
462 fn is_foreign(&self) -> bool {
463 self.flags.foreign
464 }
465
466 fn create_item_internal(
467 &self,
468 depositor: &<T>::CrossAccountId,
469 to: <T>::CrossAccountId,
470 data: CreateItemData,
471 nesting_budget: &dyn Budget,
472 ) -> Result<TokenId, sp_runtime::DispatchError> {
473 match &data {
474 up_data_structs::CreateItemData::Fungible(fungible_data) => {
475 <Pallet<T>>::create_multiple_items(
476 self,
477 &depositor,
478 [(to, fungible_data.value)].into_iter().collect(),
479 nesting_budget,
480 )?
481 }
482 _ => fail!(<CommonError<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),
483 }
484
485 Ok(TokenId::default())
486 }
487
488 fn transfer_item_internal(
489 &self,
490 depositor: &<T>::CrossAccountId,
491 from: &<T>::CrossAccountId,
492 to: &<T>::CrossAccountId,
493 token: TokenId,
494 amount: u128,
495 nesting_budget: &dyn Budget,
496 ) -> sp_runtime::DispatchResult {
497 ensure!(
498 token == TokenId::default(),
499 <CommonError<T>>::FungibleItemsHaveNoId
500 );
501
502 <Pallet<T>>::transfer_internal(self, &depositor, &from, &to, amount, nesting_budget)
503 .map(|_| ())
504 .map_err(|post_info| post_info.error)
505 }
506
507 fn burn_item_internal(
508 &self,
509 from: <T>::CrossAccountId,
510 token: TokenId,
511 amount: u128,
512 ) -> sp_runtime::DispatchResult {
513 <Self as CommonCollectionOperations<T>>::burn_item(&self, from, token, amount)
514 .map(|_| ())
515 .map_err(|post_info| post_info.error)
516 }
517}
456518
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
95use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};95use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
96use sp_std::{collections::btree_map::BTreeMap, vec::Vec};96use sp_std::{collections::btree_map::BTreeMap, vec::Vec};
97use up_data_structs::{97use up_data_structs::{
98 budget::Budget, mapping::TokenAddressMapping, AccessMode, CollectionId, CreateCollectionData,98 budget::{Budget, ZeroBudget},
99 mapping::TokenAddressMapping,
99 Property, PropertyKey, TokenId,100 AccessMode, CollectionId, CreateCollectionData, Property, PropertyKey, TokenId,
100};101};
121122
122 #[pallet::error]123 #[pallet::error]
123 pub enum Error<T> {124 pub enum Error<T> {
124 /// Not Fungible item data used to mint in Fungible collection.
125 NotFungibleDataUsedToMintFungibleCollectionToken,
126 /// Tried to set data for fungible item.125 /// Tried to set data for fungible item.
127 FungibleItemsDontHaveData,126 FungibleItemsDontHaveData,
128 /// Fungible token does not support nesting.127 /// Fungible token does not support nesting.
276 .checked_sub(amount)275 .checked_sub(amount)
277 .ok_or(<CommonError<T>>::TokenValueTooLow)?;276 .ok_or(<CommonError<T>>::TokenValueTooLow)?;
278
279 // Foreign collection check
280 ensure!(!collection.flags.foreign, <CommonError<T>>::NoPermission);
281277
282 if collection.permissions.access() == AccessMode::AllowList {278 if collection.permissions.access() == AccessMode::AllowList {
283 collection.check_allowlist(owner)?;279 collection.check_allowlist(owner)?;
310 Ok(())306 Ok(())
311 }307 }
312
313 /// Burns the specified amount of the token.
314 pub fn burn_foreign(
315 collection: &FungibleHandle<T>,
316 owner: &T::CrossAccountId,
317 amount: u128,
318 ) -> DispatchResult {
319 let total_supply = <TotalSupply<T>>::get(collection.id)
320 .checked_sub(amount)
321 .ok_or(<CommonError<T>>::TokenValueTooLow)?;
322
323 let balance = <Balance<T>>::get((collection.id, owner))
324 .checked_sub(amount)
325 .ok_or(<CommonError<T>>::TokenValueTooLow)?;
326 // =========
327
328 if balance == 0 {
329 <Balance<T>>::remove((collection.id, owner));
330 <PalletStructure<T>>::unnest_if_nested(owner, collection.id, TokenId::default());
331 } else {
332 <Balance<T>>::insert((collection.id, owner), balance);
333 }
334 <TotalSupply<T>>::insert(collection.id, total_supply);
335
336 <PalletEvm<T>>::deposit_log(
337 ERC20Events::Transfer {
338 from: *owner.as_eth(),
339 to: H160::default(),
340 value: amount.into(),
341 }
342 .to_log(collection_id_to_address(collection.id)),
343 );
344 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(
345 collection.id,
346 TokenId::default(),
347 owner.clone(),
348 amount,
349 ));
350 Ok(())
351 }
352308
353 /// Transfers the specified amount of tokens. Will check that309 /// Transfers the specified amount of tokens. Will check that
354 /// the transfer is allowed for the token.310 /// the transfer is allowed for the token.
450 }406 }
451407
452 /// Minting tokens for multiple IDs.408 /// Minting tokens for multiple IDs.
453 /// It is a utility function used in [`create_multiple_items`][`Pallet::create_multiple_items`]
454 /// and [`create_multiple_items_foreign`][`Pallet::create_multiple_items_foreign`]409 /// See [`create_item`][`Pallet::create_item`] for more details.
455 pub fn create_multiple_items_common(410 pub fn create_multiple_items(
456 collection: &FungibleHandle<T>,411 collection: &FungibleHandle<T>,
457 sender: &T::CrossAccountId,412 depositor: &T::CrossAccountId,
458 data: BTreeMap<T::CrossAccountId, u128>,413 data: BTreeMap<T::CrossAccountId, u128>,
459 nesting_budget: &dyn Budget,414 nesting_budget: &dyn Budget,
460 ) -> DispatchResult {415 ) -> DispatchResult {
416 if !collection.is_owner_or_admin(depositor) {
417 ensure!(
418 collection.permissions.mint_mode(),
419 <CommonError<T>>::PublicMintingNotAllowed
420 );
421 collection.check_allowlist(depositor)?;
422
423 for (owner, _) in data.iter() {
424 collection.check_allowlist(owner)?;
425 }
426 }
427
461 let total_supply = data428 let total_supply = data
462 .values()429 .values()
468435
469 for (to, _) in data.iter() {436 for (to, _) in data.iter() {
470 <PalletStructure<T>>::check_nesting(437 <PalletStructure<T>>::check_nesting(
471 sender,438 depositor,
472 to,439 to,
473 collection.id,440 collection.id,
474 TokenId::default(),441 TokenId::default(),
515 Ok(())482 Ok(())
516 }483 }
517
518 /// Minting tokens for multiple IDs.
519 /// See [`create_item`][`Pallet::create_item`] for more details.
520 pub fn create_multiple_items(
521 collection: &FungibleHandle<T>,
522 sender: &T::CrossAccountId,
523 data: BTreeMap<T::CrossAccountId, u128>,
524 nesting_budget: &dyn Budget,
525 ) -> DispatchResult {
526 // Foreign collection check
527 ensure!(!collection.flags.foreign, <CommonError<T>>::NoPermission);
528
529 if !collection.is_owner_or_admin(sender) {
530 ensure!(
531 collection.permissions.mint_mode(),
532 <CommonError<T>>::PublicMintingNotAllowed
533 );
534 collection.check_allowlist(sender)?;
535
536 for (owner, _) in data.iter() {
537 collection.check_allowlist(owner)?;
538 }
539 }
540
541 Self::create_multiple_items_common(collection, sender, data, nesting_budget)
542 }
543
544 /// Minting tokens for multiple IDs.
545 /// See [`create_item_foreign`][`Pallet::create_item_foreign`] for more details.
546 pub fn create_multiple_items_foreign(
547 collection: &FungibleHandle<T>,
548 sender: &T::CrossAccountId,
549 data: BTreeMap<T::CrossAccountId, u128>,
550 nesting_budget: &dyn Budget,
551 ) -> DispatchResult {
552 Self::create_multiple_items_common(collection, sender, data, nesting_budget)
553 }
554484
555 fn set_allowance_unchecked(485 fn set_allowance_unchecked(
556 collection: &FungibleHandle<T>,486 collection: &FungibleHandle<T>,
784 )714 )
785 }715 }
786
787 /// Creates fungible token.
788 ///
789 /// - `data`: Contains user who will become the owners of the tokens and amount
790 /// of tokens he will receive.
791 pub fn create_item_foreign(
792 collection: &FungibleHandle<T>,
793 sender: &T::CrossAccountId,
794 data: CreateItemData<T>,
795 nesting_budget: &dyn Budget,
796 ) -> DispatchResult {
797 Self::create_multiple_items_foreign(
798 collection,
799 sender,
800 [(data.0, data.1)].into_iter().collect(),
801 nesting_budget,
802 )
803 }
804716
805 /// Returns 10 tokens owners in no particular order717 /// Returns 10 tokens owners in no particular order
806 ///718 ///
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
19use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};19use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};
20use pallet_common::{20use pallet_common::{
21 weights::WeightInfo as _, with_weight, write_token_properties_total_weight,21 weights::WeightInfo as _, with_weight, write_token_properties_total_weight,
22 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions,22 CommonCollectionOperations, CommonWeightInfo, SelfWeightOf as PalletCommonWeightOf,
23 SelfWeightOf as PalletCommonWeightOf,23 XcmExtensions,
24};24};
25use pallet_structure::Pallet as PalletStructure;25use pallet_structure::Pallet as PalletStructure;
26use sp_runtime::DispatchError;26use sp_runtime::DispatchError;
543 }543 }
544 }544 }
545545
546 fn xcm_extensions(&self) -> Option<&dyn XcmExtensions<T>> {
547 Some(self)
548 }
549
546 fn set_allowance_for_all(550 fn set_allowance_for_all(
547 &self,551 &self,
548 owner: T::CrossAccountId,552 owner: T::CrossAccountId,
564 <Pallet<T>>::repair_item(self, token),568 <Pallet<T>>::repair_item(self, token),
565 <CommonWeights<T>>::force_repair_item(),569 <CommonWeights<T>>::force_repair_item(),
566 )570 )
571 }
572}
573
574impl<T: Config> XcmExtensions<T> for NonfungibleHandle<T> {
575 fn is_foreign(&self) -> bool {
576 self.flags.foreign
577 }
578
579 fn create_item_internal(
580 &self,
581 depositor: &<T>::CrossAccountId,
582 to: <T>::CrossAccountId,
583 data: up_data_structs::CreateItemData,
584 nesting_budget: &dyn Budget,
585 ) -> Result<TokenId, sp_runtime::DispatchError> {
586 <Pallet<T>>::create_multiple_items(
587 self,
588 &depositor,
589 vec![map_create_data::<T>(data, &to)?],
590 nesting_budget,
591 )?;
592
593 Ok(self.last_token_id())
594 }
595
596 fn transfer_item_internal(
597 &self,
598 depositor: &<T>::CrossAccountId,
599 from: &<T>::CrossAccountId,
600 to: &<T>::CrossAccountId,
601 token: TokenId,
602 amount: u128,
603 nesting_budget: &dyn Budget,
604 ) -> sp_runtime::DispatchResult {
605 ensure!(amount == 1, <Error<T>>::NonfungibleItemsHaveNoAmount);
606
607 <Pallet<T>>::transfer_internal(self, &depositor, &from, &to, token, nesting_budget)
608 .map(|_| ())
609 .map_err(|post_info| post_info.error)
610 }
611
612 fn burn_item_internal(
613 &self,
614 from: T::CrossAccountId,
615 token: TokenId,
616 amount: u128,
617 ) -> sp_runtime::DispatchResult {
618 ensure!(amount == 1, <Error<T>>::NonfungibleItemsHaveNoAmount);
619
620 <Pallet<T>>::burn(self, &from, token)
567 }621 }
568}622}
569623
modifiedprimitives/data-structs/src/budget.rsdiffbeforeafterboth
37 }37 }
38}38}
39
40pub struct ZeroBudget;
41impl Budget for ZeroBudget {
42 fn consume_custom(&self, _calls: u32) -> bool {
43 false
44 }
45}
3946
modifiedruntime/common/config/pallets/foreign_asset.rsdiffbeforeafterboth
1use frame_support::{parameter_types, PalletId};1use frame_support::{parameter_types, PalletId};
2use pallet_evm::account::CrossAccountId;
3use sp_core::H160;
4use staging_xcm::prelude::*;
5use staging_xcm_builder::AccountKey20Aliases;
26
3use crate::{runtime_common::config::governance, Runtime, RuntimeEvent};7use crate::{
8 runtime_common::config::{
9 ethereum::CrossAccountId as ConfigCrossAccountId,
10 governance,
11 xcm::{LocationToAccountId, SelfLocation},
12 },
13 RelayNetwork, Runtime, RuntimeEvent,
14};
415
5parameter_types! {16parameter_types! {
6 pub ForeignAssetPalletId: PalletId = PalletId(*b"frgnasts");17 pub ForeignAssetPalletId: PalletId = PalletId(*b"frgnasts");
7}18}
19
20pub struct LocationToCrossAccountId;
21impl staging_xcm_executor::traits::ConvertLocation<ConfigCrossAccountId>
22 for LocationToCrossAccountId
23{
24 fn convert_location(location: &MultiLocation) -> Option<ConfigCrossAccountId> {
25 LocationToAccountId::convert_location(location)
26 .map(|sub| ConfigCrossAccountId::from_sub(sub))
27 .or_else(|| {
28 let eth_address =
29 AccountKey20Aliases::<RelayNetwork, H160>::convert_location(location)?;
30
31 Some(ConfigCrossAccountId::from_eth(eth_address))
32 })
33 }
34}
835
9impl pallet_foreign_assets::Config for Runtime {36impl pallet_foreign_assets::Config for Runtime {
10 type RuntimeEvent = RuntimeEvent;37 type RuntimeEvent = RuntimeEvent;
11 type ForceRegisterOrigin = governance::RootOrTechnicalCommitteeMember;38 type ForceRegisterOrigin = governance::RootOrTechnicalCommitteeMember;
12 type PalletId = ForeignAssetPalletId;39 type PalletId = ForeignAssetPalletId;
40 type SelfLocation = SelfLocation;
41 type LocationToAccountId = LocationToCrossAccountId;
13 type WeightInfo = pallet_foreign_assets::weights::SubstrateWeight<Self>;42 type WeightInfo = pallet_foreign_assets::weights::SubstrateWeight<Self>;
14}43}
1544