-
Notifications
You must be signed in to change notification settings - Fork 300
use relaychain asset as fee #700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 17 commits
69165e6
30cce9d
d14ccf1
9344a77
67ed76e
9af1b35
616be9f
97e0f78
f9cbfed
bd48f89
281bef4
6877a4d
065e50b
dbfc6e6
c29e8cd
34241d2
67d76e6
a74cb4a
85fb142
085806b
69acc52
662981c
dba578f
83e0304
cf3d8aa
a2d1de5
cadcc9f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -54,7 +54,6 @@ use TransferKind::*; | |
|
|
||
| #[frame_support::pallet] | ||
| pub mod module { | ||
|
|
||
| use super::*; | ||
|
|
||
| #[pallet::config] | ||
|
|
@@ -571,34 +570,121 @@ pub mod module { | |
| assets.len() <= T::MaxAssetsForTransfer::get(), | ||
| Error::<T>::TooManyAssetsBeingSent | ||
| ); | ||
| let origin_location = T::AccountIdToMultiLocation::convert(who.clone()); | ||
|
|
||
| let fee_to_dest = reset_fee(&fee, dest_weight as u128); | ||
|
|
||
| // We check that all assets are valid and share the same reserve | ||
| for i in 0..assets.len() { | ||
| let mut non_fee_reserve: Option<MultiLocation> = None; | ||
| let asset_len = assets.len(); | ||
| let mut assets_to_dest = MultiAssets::new(); | ||
| for i in 0..asset_len { | ||
| let asset = assets.get(i).ok_or(Error::<T>::AssetIndexNonExistent)?; | ||
| if !asset.is_fungible(None) { | ||
| return Err(Error::<T>::NotFungible.into()); | ||
| } | ||
| if fungible_amount(asset).is_zero() { | ||
| return Ok(()); | ||
|
xlc marked this conversation as resolved.
Outdated
|
||
| } | ||
| ensure!( | ||
| fee.reserve() == asset.reserve(), | ||
| Error::<T>::DistinctReserveForAssetAndFee | ||
| ); | ||
| if fee != *asset { | ||
| assets_to_dest.push(asset.clone()); | ||
| } else { | ||
| assets_to_dest.push(fee_to_dest.clone()); | ||
| } | ||
| // `assets` includes fee, the reserve location is decided by non fee asset | ||
| if (fee != *asset && non_fee_reserve.is_none()) || asset_len == 1 { | ||
| non_fee_reserve = asset.reserve(); | ||
| } | ||
| // make sure all non fee assets share the same reserve | ||
| if non_fee_reserve.is_some() { | ||
| ensure!( | ||
| non_fee_reserve == asset.reserve(), | ||
| Error::<T>::DistinctReserveForAssetAndFee | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| // In case that fee reserve != asset reserve, there're two xcm sent from sender. | ||
| // first xcm send to fee reserve which also route to dest. second xcm directly | ||
| // send to dest. the fee amount in fee asset is split into two parts. | ||
| // 1. assets send to fee reserve = fee_amount - dest_weight | ||
| // 2. assets send to dest reserve = dest_weight | ||
| // the first part + second part = fee amount in fee asset | ||
| let fee_reserve = fee.reserve(); | ||
| if fee_reserve != non_fee_reserve { | ||
| let mut assets_to_fee_reserve = MultiAssets::new(); | ||
| let asset_to_fee_reserve = subtract_fee(&fee, dest_weight as u128); | ||
| assets_to_fee_reserve.push(asset_to_fee_reserve.clone()); | ||
|
|
||
| // First xcm send to fee reserve chain and routing to dest chain. | ||
| // The `SelfLocation` current is (1, Parachain(id)) refer to sender parachain. | ||
| // we use `SelfLocation` to fund fee to sender's parachain account on | ||
| // destination chain, which asset is origin from sender account on sender chain. | ||
| // Notice: if parachain set `SelfLocation` to (0, Here), then it'll be error! | ||
| Self::send_xcm( | ||
| origin_location.clone(), | ||
| assets_to_fee_reserve, | ||
| asset_to_fee_reserve, | ||
| fee_reserve, | ||
| &dest, | ||
| Some(T::SelfLocation::get()), | ||
| dest_weight, | ||
| )?; | ||
|
|
||
| // Second xcm send to dest chain. | ||
| Self::send_xcm( | ||
| origin_location, | ||
| assets_to_dest, | ||
| fee_to_dest, | ||
| non_fee_reserve, | ||
| &dest, | ||
| None, | ||
| dest_weight, | ||
| )?; | ||
| } else { | ||
| Self::send_xcm( | ||
| origin_location, | ||
| assets.clone(), | ||
| fee, | ||
| non_fee_reserve, | ||
| &dest, | ||
| None, | ||
| dest_weight, | ||
| )?; | ||
| } | ||
|
|
||
| let (transfer_kind, dest, reserve, recipient) = Self::transfer_kind(&fee, &dest)?; | ||
| if deposit_event { | ||
| Self::deposit_event(Event::<T>::TransferredMultiAssets { | ||
| sender: who, | ||
| assets, | ||
| dest, | ||
| }); | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| /// Send xcm with given assets and fee to dest or reserve chain. | ||
| fn send_xcm( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. need a better naming
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rename to |
||
| origin_location: MultiLocation, | ||
| assets: MultiAssets, | ||
| fee: MultiAsset, | ||
| reserve: Option<MultiLocation>, | ||
| dest: &MultiLocation, | ||
| manual_recipient: Option<MultiLocation>, | ||
|
zqhxuyuan marked this conversation as resolved.
Outdated
|
||
| dest_weight: Weight, | ||
| ) -> DispatchResult { | ||
| let (transfer_kind, dest, reserve, recipient) = Self::transfer_kind(reserve, dest)?; | ||
| let recipient = match manual_recipient { | ||
| Some(recipient) => recipient, | ||
| None => recipient, | ||
| }; | ||
|
|
||
| let mut msg = match transfer_kind { | ||
| SelfReserveAsset => { | ||
| Self::transfer_self_reserve_asset(assets.clone(), fee, dest.clone(), recipient, dest_weight)? | ||
| } | ||
| ToReserve => Self::transfer_to_reserve(assets.clone(), fee, dest.clone(), recipient, dest_weight)?, | ||
| ToNonReserve => { | ||
| Self::transfer_to_non_reserve(assets.clone(), fee, reserve, dest.clone(), recipient, dest_weight)? | ||
| } | ||
| SelfReserveAsset => Self::transfer_self_reserve_asset(assets, fee, dest, recipient, dest_weight)?, | ||
| ToReserve => Self::transfer_to_reserve(assets, fee, dest, recipient, dest_weight)?, | ||
| ToNonReserve => Self::transfer_to_non_reserve(assets, fee, reserve, dest, recipient, dest_weight)?, | ||
| }; | ||
|
|
||
| let origin_location = T::AccountIdToMultiLocation::convert(who.clone()); | ||
| let weight = T::Weigher::weight(&mut msg).map_err(|()| Error::<T>::UnweighableMessage)?; | ||
| T::XcmExecutor::execute_xcm_in_credit(origin_location, msg, weight, weight) | ||
| .ensure_complete() | ||
|
|
@@ -607,14 +693,6 @@ pub mod module { | |
| Error::<T>::XcmExecutionFailed | ||
| })?; | ||
|
|
||
| if deposit_event { | ||
| Self::deposit_event(Event::<T>::TransferredMultiAssets { | ||
| sender: who, | ||
| assets, | ||
| dest, | ||
| }); | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
|
|
@@ -735,22 +813,22 @@ pub mod module { | |
|
|
||
| /// Get the transfer kind. | ||
| /// | ||
| /// Returns `Err` if `asset` and `dest` combination doesn't make sense, | ||
| /// else returns a tuple of: | ||
| /// Returns `Err` if `dest` combination doesn't make sense, or `reserve` | ||
| /// is none, else returns a tuple of: | ||
| /// - `transfer_kind`. | ||
| /// - asset's `reserve` parachain or relay chain location, | ||
| /// - `dest` parachain or relay chain location. | ||
| /// - `recipient` location. | ||
| fn transfer_kind( | ||
| asset: &MultiAsset, | ||
| reserve: Option<MultiLocation>, | ||
| dest: &MultiLocation, | ||
| ) -> Result<(TransferKind, MultiLocation, MultiLocation, MultiLocation), DispatchError> { | ||
| let (dest, recipient) = Self::ensure_valid_dest(dest)?; | ||
|
|
||
| let self_location = T::SelfLocation::get(); | ||
| ensure!(dest != self_location, Error::<T>::NotCrossChainTransfer); | ||
|
|
||
| let reserve = asset.reserve().ok_or(Error::<T>::AssetHasNoReserve)?; | ||
| let reserve = reserve.ok_or(Error::<T>::AssetHasNoReserve)?; | ||
| let transfer_kind = if reserve == self_location { | ||
| SelfReserveAsset | ||
| } else if reserve == dest { | ||
|
|
@@ -766,13 +844,13 @@ pub mod module { | |
| impl<T: Config> Pallet<T> { | ||
| /// Returns weight of `transfer_multiasset` call. | ||
| fn weight_of_transfer_multiasset(asset: &VersionedMultiAsset, dest: &VersionedMultiLocation) -> Weight { | ||
| let asset = asset.clone().try_into(); | ||
| let asset: Result<MultiAsset, _> = asset.clone().try_into(); | ||
| let dest = dest.clone().try_into(); | ||
| if let (Ok(asset), Ok(dest)) = (asset, dest) { | ||
| if let Ok((transfer_kind, dest, _, reserve)) = Self::transfer_kind(&asset, &dest) { | ||
| if let Ok((transfer_kind, dest, _, reserve)) = Self::transfer_kind(asset.reserve(), &dest) { | ||
| let mut msg = match transfer_kind { | ||
| SelfReserveAsset => Xcm(vec![ | ||
| WithdrawAsset(MultiAssets::from(asset.clone())), | ||
| WithdrawAsset(MultiAssets::from(asset)), | ||
| DepositReserveAsset { | ||
| assets: All.into(), | ||
| max_assets: 1, | ||
|
|
@@ -781,7 +859,7 @@ pub mod module { | |
| }, | ||
| ]), | ||
| ToReserve | ToNonReserve => Xcm(vec![ | ||
| WithdrawAsset(MultiAssets::from(asset.clone())), | ||
| WithdrawAsset(MultiAssets::from(asset)), | ||
| InitiateReserveWithdraw { | ||
| assets: All.into(), | ||
| // `dest` is always (equal to) `reserve` in both cases | ||
|
|
@@ -833,38 +911,53 @@ pub mod module { | |
| dest: &VersionedMultiLocation, | ||
| ) -> Weight { | ||
| let assets: Result<MultiAssets, ()> = assets.clone().try_into(); | ||
|
|
||
| let dest = dest.clone().try_into(); | ||
| if let (Ok(assets), Ok(dest)) = (assets, dest) { | ||
| if let Some(fee) = assets.get(*fee_item as usize) { | ||
| if let Ok((transfer_kind, dest, _, reserve)) = Self::transfer_kind(fee, &dest) { | ||
| let mut msg = match transfer_kind { | ||
| SelfReserveAsset => Xcm(vec![ | ||
| WithdrawAsset(assets.clone()), | ||
| DepositReserveAsset { | ||
| assets: All.into(), | ||
| max_assets: assets.len() as u32, | ||
| dest, | ||
| xcm: Xcm(vec![]), | ||
| }, | ||
| ]), | ||
| ToReserve | ToNonReserve => Xcm(vec![ | ||
| WithdrawAsset(assets), | ||
| InitiateReserveWithdraw { | ||
| assets: All.into(), | ||
| // `dest` is always (equal to) `reserve` in both cases | ||
| reserve, | ||
| xcm: Xcm(vec![]), | ||
| }, | ||
| ]), | ||
| }; | ||
| return T::Weigher::weight(&mut msg) | ||
| .map_or(Weight::max_value(), |w| T::BaseXcmWeight::get().saturating_add(w)); | ||
| } | ||
| let reserve_location = Self::get_reserve_location(&assets, fee_item); | ||
| // if let Ok(reserve_location) = reserve_location { | ||
| if let Ok((transfer_kind, dest, _, reserve)) = Self::transfer_kind(reserve_location, &dest) { | ||
| let mut msg = match transfer_kind { | ||
| SelfReserveAsset => Xcm(vec![ | ||
| WithdrawAsset(assets.clone()), | ||
| DepositReserveAsset { | ||
| assets: All.into(), | ||
| max_assets: assets.len() as u32, | ||
| dest, | ||
| xcm: Xcm(vec![]), | ||
| }, | ||
| ]), | ||
| ToReserve | ToNonReserve => Xcm(vec![ | ||
| WithdrawAsset(assets), | ||
| InitiateReserveWithdraw { | ||
| assets: All.into(), | ||
| // `dest` is always (equal to) `reserve` in both cases | ||
| reserve, | ||
| xcm: Xcm(vec![]), | ||
| }, | ||
| ]), | ||
| }; | ||
| return T::Weigher::weight(&mut msg) | ||
| .map_or(Weight::max_value(), |w| T::BaseXcmWeight::get().saturating_add(w)); | ||
| } | ||
| // } | ||
| } | ||
| 0 | ||
| } | ||
|
|
||
| /// Get reserve location by `assets` and `fee_item`. the `assets` | ||
| /// includes fee asset and non fee asset. make sure assets have ge one | ||
| /// asset. all non fee asset should share same reserve location. | ||
| fn get_reserve_location(assets: &MultiAssets, fee_item: &u32) -> Option<MultiLocation> { | ||
| let reserve_idx = if assets.len() == 1 { | ||
| 0 | ||
| } else if *fee_item == 0 { | ||
| 1 | ||
| } else { | ||
| 0 | ||
| }; | ||
| let asset = assets.get(reserve_idx); | ||
| asset.and_then(|a| a.reserve()) | ||
| } | ||
| } | ||
|
|
||
| impl<T: Config> XcmTransfer<T::AccountId, T::Balance, T::CurrencyId> for Pallet<T> { | ||
|
|
@@ -909,3 +1002,18 @@ fn half(asset: &MultiAsset) -> MultiAsset { | |
| id: asset.id.clone(), | ||
| } | ||
| } | ||
|
|
||
| fn subtract_fee(asset: &MultiAsset, amount: u128) -> MultiAsset { | ||
| let final_amount = fungible_amount(asset).checked_sub(amount).expect("fee too low; qed"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we checked before subtract, so it's ok here I think |
||
| MultiAsset { | ||
| fun: Fungible(final_amount), | ||
| id: asset.id.clone(), | ||
| } | ||
| } | ||
|
zqhxuyuan marked this conversation as resolved.
|
||
|
|
||
| fn reset_fee(asset: &MultiAsset, amount: u128) -> MultiAsset { | ||
| MultiAsset { | ||
| fun: Fungible(amount), | ||
| id: asset.id.clone(), | ||
| } | ||
| } | ||
|
zqhxuyuan marked this conversation as resolved.
Outdated
|
||
Uh oh!
There was an error while loading. Please reload this page.