git.delta.rocks / unique-network / refs/commits / 68fcead157ea

difftreelog

chore foreign-assets docs and minor improvements

Daniel Shiposha2023-10-18parent: #fd75004.patch.diff
in: master

1 file changed

modifiedpallets/foreign-assets/src/lib.rsdiffbeforeafterboth
216 .expect("key length < max property key length; qed")216 .expect("key length < max property key length; qed")
217 }217 }
218218
219 /// Converts a multilocation to the Unique Network's local collection
220 /// (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 corresponds
226 /// 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 }
244256
257 /// 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 location
260 /// 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 corresponding
264 /// 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 }
254276
277 /// 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 }
267296
268 /// 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 collection
271 /// 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 }
288320
321 /// 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();
296329
297 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"))?;
314345
315 <ForeignReserveAssetInstanceToTokenId<T>>::insert(346 <ForeignReserveAssetInstanceToTokenId<T>>::insert(
316 collection_id,347 collection_id,
321 Ok(())352 Ok(())
322 }353 }
323354
355 /// Deposits an asset instance to the `to` account.
356 ///
357 /// Either transfers an existing item from the pallet's account
358 /// 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;
336371
337 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 };
376
377 deposit_result
378 .map_err(|_| XcmError::FailedToTransactAsset("non-fungible item deposit failed"))
343 }379 }
380
381 /// 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)?;
394
395 if xcm_ext.token_has_children(token_id) {
396 return Err(XcmError::Unimplemented);
397 }
398
399 let depositor = &from;
400 let to = Self::pallet_account();
401 let amount = 1;
402 xcm_ext
403 .transfer_item(depositor, &from, &to, token_id, amount, &ZeroBudget)
404 .map_err(|_| XcmError::FailedToTransactAsset("nonfungible item withdraw failed"))?;
405
406 Ok(())
407 }
344}408}
345409
346impl<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) {}
366430
367 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)?;
434
368 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)?;
374
375 let to = T::LocationToAccountId::convert_location(to)
376 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;
377441
378 match what.fun {442 match what.fun {
379 Fungibility::Fungible(amount) => xcm_ext443 Fungibility::Fungible(amount) => xcm_ext
387 .map_err(|_| XcmError::FailedToTransactAsset("fungible item deposit failed")),451 .map_err(|_| XcmError::FailedToTransactAsset("fungible item deposit failed")),
388452
389 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"))?,
414478
415 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)?;
419
420 if xcm_ext.token_has_children(token_id) {
421 return Err(XcmError::Unimplemented);
422 }
423
424 let depositor = &from;
425 let to = Self::pallet_account();
426 let amount = 1;
427 xcm_ext
428 .transfer_item(depositor, &from, &to, token_id, amount, &ZeroBudget)
429 .map_err(|_| {
430 XcmError::FailedToTransactAsset("nonfungible item withdraw failed")
431 })?;
432 }481 }
433 }482 }
434483
441 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)?;
495
496 let to = T::LocationToAccountId::convert_location(to)
497 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;
498
444 let collection_id = Self::multiasset_to_collection(what)?;499 let collection_id = Self::multiasset_to_collection(what)?;
445500
448 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)?;
450505
451 let from = T::LocationToAccountId::convert_location(from)506 let depositor = &from;
452 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;
453507
454 let to = T::LocationToAccountId::convert_location(to)508 let token_id;
455 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;509 let amount;
456
457 let depositor = &from;510 let map_error: fn(DispatchError) -> XcmError;
458511
459 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 }
470518
471 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)?;
475523
476 let amount = 1;524 amount = 1;
477
478 xcm_ext
479 .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 }
528
529 xcm_ext
530 .transfer_item(depositor, &from, &to, token_id, amount, &ZeroBudget)
531 .map_err(map_error)?;
485532
486 Ok(what.clone().into())533 Ok(what.clone().into())
487 }534 }