difftreelog
chore foreign-assets docs and minor improvements
in: master
1 file changed
pallets/foreign-assets/src/lib.rsdiffbeforeafterboth216 .expect("key length < max property key length; qed")216 .expect("key length < max property key length; qed")217 }217 }218218219 /// Converts a multilocation to the Unique Network's local collection220 /// (i.e. the collection originally created on the Unique Network's parachain).221 ///222 /// The multilocation corresponds to a Unique Network's collection if:223 /// * It is `Here` location that corresponds to the native token of this parachain.224 /// * It is `../Parachain(<Unique Network Para ID>)` that also corresponds to the native token of this parachain.225 /// * It is `../Parachain(<Unique Network Para ID>)/GeneralIndex(<Collection ID>)` that corresponds226 /// to the collection with the ID equal to `<Collection ID>`. The `<Collection ID>` must be in the valid range,227 /// otherwise the `AssetIdConversionFailed` error will be returned.228 ///229 /// If the multilocation doesn't match the patterns listed above, the function returns `Ok(None)`,230 /// identifying that the given multilocation doesn't correspond to a local collection.219 fn native_asset_location_to_collection(231 fn native_asset_location_to_collection(220 asset_location: &MultiLocation,232 asset_location: &MultiLocation,221 ) -> Result<Option<CollectionId>, XcmError> {233 ) -> Result<Option<CollectionId>, XcmError> {242 }254 }243 }255 }244256257 /// Converts a multiasset to a Unique Network's collection (either local or the foreign one).258 ///259 /// The function will try to convert the multiasset's reserve location260 /// to the Unique Network's local collection.261 ///262 /// If the multilocation doesn't correspond to a local collection,263 /// the function will check if the reserve location has the corresponding264 /// derivative Unique Network's collection, and will return the said collection ID if found.265 ///266 /// If all of the above have failed, the `AssetIdConversionFailed` error will be returned.245 fn multiasset_to_collection(asset: &MultiAsset) -> Result<CollectionId, XcmError> {267 fn multiasset_to_collection(asset: &MultiAsset) -> Result<CollectionId, XcmError> {246 let AssetId::Concrete(asset_reserve_location) = asset.id else {268 let AssetId::Concrete(asset_reserve_location) = asset.id else {247 return Err(XcmExecutorError::AssetNotHandled.into());269 return Err(XcmExecutorError::AssetNotHandled.into());252 .ok_or_else(|| XcmExecutorError::AssetIdConversionFailed.into())274 .ok_or_else(|| XcmExecutorError::AssetIdConversionFailed.into())253 }275 }254276277 /// Converts an XCM asset instance to the Unique Network's token ID.278 ///279 /// The asset instance corresponds to the Unique Network's token ID if it is in the following format:280 /// `AssetInstance::Index(<token ID>)`.281 ///282 /// If the asset instance is not in the valid format or the `<token ID>` points to a non-existent token,283 /// the `AssetNotFound` error will be returned.255 fn native_asset_instance_to_token_id(284 fn native_asset_instance_to_token_id(256 asset_instance: &AssetInstance,285 asset_instance: &AssetInstance,257 ) -> Result<TokenId, XcmError> {286 ) -> Result<TokenId, XcmError> {265 }294 }266 }295 }267296268 /// Obtains the token id of the `asset_instance` in the collection.297 /// Obtains the token ID of the `asset_instance` in the collection.269 ///298 ///270 /// Returns `Ok(None)` only if the `asset_instance` points to a foreign item299 /// Returns `Ok(None)` only if the `asset_instance` is a part of a foreign collection271 /// and it haven't been created on this blockchain yet.300 /// and the item hasn't yet been created on this blockchain.301 ///302 /// If the `asset_instance` exists and it is a part of a foreign collection, the function will return `Ok(Some(<token ID>))`.272 ///303 ///273 /// If the `asset_instance` points to a native item, it cannot return `Ok(None)`.304 /// If the `asset_instance` is a part of a local collection,305 /// the function will return either `Ok(Some(<token ID>))` or an error if the token is not found.274 fn asset_instance_to_token_id(306 fn asset_instance_to_token_id(275 xcm_ext: &dyn XcmExtensions<T>,307 xcm_ext: &dyn XcmExtensions<T>,276 collection_id: CollectionId,308 collection_id: CollectionId,286 }318 }287 }319 }288320321 /// Creates a foreign item in the the collection.289 fn create_foreign_asset_instance(322 fn create_foreign_asset_instance(290 xcm_ext: &dyn XcmExtensions<T>,323 xcm_ext: &dyn XcmExtensions<T>,291 collection_id: CollectionId,324 collection_id: CollectionId,292 asset_instance: &AssetInstance,325 asset_instance: &AssetInstance,293 to: T::CrossAccountId,326 to: T::CrossAccountId,294 ) -> XcmResult {327 ) -> DispatchResult {295 let asset_instance_encoded = asset_instance.encode();328 let asset_instance_encoded = asset_instance.encode();296329297 let derivative_token_id = xcm_ext330 let derivative_token_id = xcm_ext.create_item(310 }),342 }),311 &ZeroBudget,343 &ZeroBudget,312 )344 )?;313 .map_err(|_| XcmError::FailedToTransactAsset("non-fungible item deposit failed"))?;314345315 <ForeignReserveAssetInstanceToTokenId<T>>::insert(346 <ForeignReserveAssetInstanceToTokenId<T>>::insert(316 collection_id,347 collection_id,321 Ok(())352 Ok(())322 }353 }323354355 /// Deposits an asset instance to the `to` account.356 ///357 /// Either transfers an existing item from the pallet's account358 /// or creates a foreign item.324 fn deposit_asset_instance(359 fn deposit_asset_instance(325 xcm_ext: &dyn XcmExtensions<T>,360 xcm_ext: &dyn XcmExtensions<T>,326 collection_id: CollectionId,361 collection_id: CollectionId,362 asset_instance: &AssetInstance,327 to: T::CrossAccountId,363 to: T::CrossAccountId,328 asset_instance: &AssetInstance,329 ) -> XcmResult {364 ) -> XcmResult {330 if let Some(token_id) =365 let deposit_result = if let Some(token_id) =331 Self::asset_instance_to_token_id(xcm_ext, collection_id, asset_instance)?366 Self::asset_instance_to_token_id(xcm_ext, collection_id, asset_instance)?332 {367 {333 let depositor = &Self::pallet_account();368 let depositor = &Self::pallet_account();334 let from = depositor;369 let from = depositor;335 let amount = 1;370 let amount = 1;336371337 xcm_ext372 xcm_ext.transfer_item(depositor, from, &to, token_id, amount, &ZeroBudget)338 .transfer_item(depositor, from, &to, token_id, amount, &ZeroBudget)339 .map_err(|_| XcmError::FailedToTransactAsset("non-fungible item deposit failed"))340 } else {373 } else {341 Self::create_foreign_asset_instance(xcm_ext, collection_id, asset_instance, to)374 Self::create_foreign_asset_instance(xcm_ext, collection_id, asset_instance, to)342 }375 };376377 deposit_result378 .map_err(|_| XcmError::FailedToTransactAsset("non-fungible item deposit failed"))343 }379 }380381 /// Withdraws an asset instance from the `from` account.382 ///383 /// Transfers the asset instance to the pallet's account.384 ///385 /// Won't withdraw the instance if it has children.386 fn withdraw_asset_instance(387 xcm_ext: &dyn XcmExtensions<T>,388 collection_id: CollectionId,389 asset_instance: &AssetInstance,390 from: T::CrossAccountId,391 ) -> XcmResult {392 let token_id = Self::asset_instance_to_token_id(xcm_ext, collection_id, &asset_instance)?393 .ok_or(XcmError::AssetNotFound)?;394395 if xcm_ext.token_has_children(token_id) {396 return Err(XcmError::Unimplemented);397 }398399 let depositor = &from;400 let to = Self::pallet_account();401 let amount = 1;402 xcm_ext403 .transfer_item(depositor, &from, &to, token_id, amount, &ZeroBudget)404 .map_err(|_| XcmError::FailedToTransactAsset("nonfungible item withdraw failed"))?;405406 Ok(())407 }344}408}345409346impl<T: Config> TransactAsset for Pallet<T> {410impl<T: Config> TransactAsset for Pallet<T> {365 fn check_out(_dest: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {}429 fn check_out(_dest: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {}366430367 fn deposit_asset(what: &MultiAsset, to: &MultiLocation, _context: &XcmContext) -> XcmResult {431 fn deposit_asset(what: &MultiAsset, to: &MultiLocation, _context: &XcmContext) -> XcmResult {432 let to = T::LocationToAccountId::convert_location(to)433 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;434368 let collection_id = Self::multiasset_to_collection(what)?;435 let collection_id = Self::multiasset_to_collection(what)?;369 let dispatch =436 let dispatch =372 let collection = dispatch.as_dyn();439 let collection = dispatch.as_dyn();373 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::Unimplemented)?;440 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::Unimplemented)?;374375 let to = T::LocationToAccountId::convert_location(to)376 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;377441378 match what.fun {442 match what.fun {379 Fungibility::Fungible(amount) => xcm_ext443 Fungibility::Fungible(amount) => xcm_ext387 .map_err(|_| XcmError::FailedToTransactAsset("fungible item deposit failed")),451 .map_err(|_| XcmError::FailedToTransactAsset("fungible item deposit failed")),388452389 Fungibility::NonFungible(asset_instance) => {453 Fungibility::NonFungible(asset_instance) => {390 Self::deposit_asset_instance(xcm_ext, collection_id, to, &asset_instance)454 Self::deposit_asset_instance(xcm_ext, collection_id, &asset_instance, to)391 }455 }392 }456 }393 }457 }413 .map_err(|_| XcmError::FailedToTransactAsset("fungible item withdraw failed"))?,477 .map_err(|_| XcmError::FailedToTransactAsset("fungible item withdraw failed"))?,414478415 Fungibility::NonFungible(asset_instance) => {479 Fungibility::NonFungible(asset_instance) => {416 let token_id =417 Self::asset_instance_to_token_id(xcm_ext, collection_id, &asset_instance)?480 Self::withdraw_asset_instance(xcm_ext, collection_id, &asset_instance, from)?;418 .ok_or(XcmError::AssetNotFound)?;419420 if xcm_ext.token_has_children(token_id) {421 return Err(XcmError::Unimplemented);422 }423424 let depositor = &from;425 let to = Self::pallet_account();426 let amount = 1;427 xcm_ext428 .transfer_item(depositor, &from, &to, token_id, amount, &ZeroBudget)429 .map_err(|_| {430 XcmError::FailedToTransactAsset("nonfungible item withdraw failed")431 })?;432 }481 }433 }482 }434483441 to: &MultiLocation,490 to: &MultiLocation,442 _context: &XcmContext,491 _context: &XcmContext,443 ) -> Result<staging_xcm_executor::Assets, XcmError> {492 ) -> Result<staging_xcm_executor::Assets, XcmError> {493 let from = T::LocationToAccountId::convert_location(from)494 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;495496 let to = T::LocationToAccountId::convert_location(to)497 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;498444 let collection_id = Self::multiasset_to_collection(what)?;499 let collection_id = Self::multiasset_to_collection(what)?;445500448 let collection = dispatch.as_dyn();503 let collection = dispatch.as_dyn();449 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::NoPermission)?;504 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::NoPermission)?;450505451 let from = T::LocationToAccountId::convert_location(from)506 let depositor = &from;452 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;453507454 let to = T::LocationToAccountId::convert_location(to)508 let token_id;455 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;509 let amount;456457 let depositor = &from;510 let map_error: fn(DispatchError) -> XcmError;458511459 match what.fun {512 match what.fun {460 Fungibility::Fungible(amount) => xcm_ext513 Fungibility::Fungible(fungible_amount) => {461 .transfer_item(514 token_id = TokenId::default();462 depositor,515 amount = fungible_amount;463 &from,464 &to,465 TokenId::default(),466 amount,467 &ZeroBudget,468 )469 .map_err(|_| XcmError::FailedToTransactAsset("fungible item transfer failed"))?,516 map_error = |_| XcmError::FailedToTransactAsset("fungible item transfer failed");517 }470518471 Fungibility::NonFungible(asset_instance) => {519 Fungibility::NonFungible(asset_instance) => {472 let token_id =520 token_id =473 Self::asset_instance_to_token_id(xcm_ext, collection_id, &asset_instance)?521 Self::asset_instance_to_token_id(xcm_ext, collection_id, &asset_instance)?474 .ok_or(XcmError::AssetNotFound)?;522 .ok_or(XcmError::AssetNotFound)?;475523476 let amount = 1;524 amount = 1;477478 xcm_ext479 .transfer_item(depositor, &from, &to, token_id, amount, &ZeroBudget)480 .map_err(|_| {525 map_error = |_| XcmError::FailedToTransactAsset("nonfungible item transfer failed")481 XcmError::FailedToTransactAsset("nonfungible item transfer failed")482 })?;483 }526 }484 }527 }528529 xcm_ext530 .transfer_item(depositor, &from, &to, token_id, amount, &ZeroBudget)531 .map_err(map_error)?;485532486 Ok(what.clone().into())533 Ok(what.clone().into())487 }534 }