1234567891011121314151617use frame_support::{18 traits::{19 Contains, tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Get,20 Everything, fungibles,21 },22 weights::{Weight, WeightToFeePolynomial, WeightToFee},23 parameter_types, match_types,24};25use frame_system::EnsureRoot;26use sp_runtime::{27 traits::{Saturating, CheckedConversion, Zero},28 SaturatedConversion,29};30use pallet_xcm::XcmPassthrough;31use polkadot_parachain::primitives::Sibling;32use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};33use xcm::latest::{34 AssetId::{Concrete},35 Fungibility::Fungible as XcmFungible,36 MultiAsset, Error as XcmError, Instruction, Xcm,37};38use xcm_builder::{39 AccountId32Aliases, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, EnsureXcmOrigin,40 FixedWeightBounds, FungiblesAdapter, LocationInverter, NativeAsset, ParentAsSuperuser,41 RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,42 SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,43 ParentIsPreset, ConvertedConcreteAssetId,44};45use xcm_executor::{Config, XcmExecutor, Assets};46use xcm_executor::traits::{47 Convert as ConvertXcm, JustTry, MatchesFungible, WeightTrader, FilterAssetLocation,48 ShouldExecute,49};50use pallet_foreing_assets::{51 AssetIds, AssetIdMapping, XcmForeignAssetIdMapping, CurrencyId, NativeCurrency, FreeForAll,52 TryAsForeing, ForeignAssetId,53};54use sp_std::{borrow::Borrow, marker::PhantomData, vec, vec::Vec};55use crate::{56 Runtime, Call, Event, Origin, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, XcmpQueue,57 xcm_config::Barrier,58};59#[cfg(feature = "foreign-assets")]60use crate::ForeingAssets;6162use up_common::{63 types::{AccountId, Balance},64 constants::*,65};6667parameter_types! {68 pub const RelayLocation: MultiLocation = MultiLocation::parent();69 pub const RelayNetwork: NetworkId = NetworkId::Polkadot;70 pub RelayOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into();71 pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();72}7374757677pub type LocationToAccountId = (78 79 ParentIsPreset<AccountId>,80 81 SiblingParachainConvertsVia<Sibling, AccountId>,82 83 AccountId32Aliases<RelayNetwork, AccountId>,84);8586pub struct OnlySelfCurrency;87impl<B: TryFrom<u128>> MatchesFungible<B> for OnlySelfCurrency {88 fn matches_fungible(a: &MultiAsset) -> Option<B> {89 let paraid = Parachain(ParachainInfo::parachain_id().into());90 match (&a.id, &a.fun) {91 (92 Concrete(MultiLocation {93 parents: 1,94 interior: X1(loc),95 }),96 XcmFungible(ref amount),97 ) if paraid == *loc => CheckedConversion::checked_from(*amount),98 (99 Concrete(MultiLocation {100 parents: 0,101 interior: Here,102 }),103 XcmFungible(ref amount),104 ) => CheckedConversion::checked_from(*amount),105 _ => None,106 }107 }108}109110111pub type LocalAssetTransactor = CurrencyAdapter<112 113 Balances,114 115 OnlySelfCurrency,116 117 LocationToAccountId,118 119 AccountId,120 121 (),122>;123124125pub type LocalOriginToLocation = (SignedToAccountId32<Origin, AccountId, RelayNetwork>,);126127128129pub type XcmRouter = (130 131 cumulus_primitives_utility::ParentAsUmp<ParachainSystem, ()>,132 133 XcmpQueue,134);135136137138139pub type XcmOriginToTransactDispatchOrigin = (140 141 142 143 SovereignSignedViaLocation<LocationToAccountId, Origin>,144 145 146 RelayChainAsNative<RelayOrigin, Origin>,147 148 149 SiblingParachainAsNative<cumulus_pallet_xcm::Origin, Origin>,150 151 152 ParentAsSuperuser<Origin>,153 154 155 SignedAccountId32AsNative<RelayNetwork, Origin>,156 157 XcmPassthrough<Origin>,158);159160parameter_types! {161 162 pub UnitWeightCost: Weight = 1_000_000;163 164 pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), 1_200 * UNIQUE);165 pub const MaxInstructions: u32 = 100;166}167168match_types! {169 pub type ParentOrParentsUnitPlurality: impl Contains<MultiLocation> = {170 MultiLocation { parents: 1, interior: Here } |171 MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) }172 };173}174175pub trait TryPass {176 fn try_pass<Call>(177 origin: &MultiLocation,178 message: &mut Xcm<Call>,179 ) -> Result<(), ()>;180}181182#[impl_trait_for_tuples::impl_for_tuples(30)]183impl TryPass for Tuple {184 fn try_pass<Call>(185 origin: &MultiLocation,186 message: &mut Xcm<Call>,187 ) -> Result<(), ()> {188 for_tuples!( #(189 Tuple::try_pass(origin, message)?;190 )* );191192 Ok(())193 }194}195196pub struct DenyTransact;197impl TryPass for DenyTransact {198 fn try_pass<Call>(199 _origin: &MultiLocation,200 message: &mut Xcm<Call>,201 ) -> Result<(), ()> {202 let transact_inst = message203 .0204 .iter()205 .find(|inst| matches![inst, Instruction::Transact { .. }]);206207 match transact_inst {208 Some(_) => {209 log::warn!(210 target: "xcm::barrier",211 "transact XCM rejected"212 );213214 Err(())215 }216 None => Ok(()),217 }218 }219}220221222223pub struct DenyThenTry<Deny, Allow>(PhantomData<Deny>, PhantomData<Allow>)224where225 Deny: TryPass,226 Allow: ShouldExecute;227228impl<Deny, Allow> ShouldExecute for DenyThenTry<Deny, Allow>229where230 Deny: TryPass,231 Allow: ShouldExecute,232{233 fn should_execute<Call>(234 origin: &MultiLocation,235 message: &mut Xcm<Call>,236 max_weight: Weight,237 weight_credit: &mut Weight,238 ) -> Result<(), ()> {239 Deny::try_pass(origin, message)?;240 Allow::should_execute(origin, message, max_weight, weight_credit)241 }242}243244pub struct UsingOnlySelfCurrencyComponents<245 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,246 AssetId: Get<MultiLocation>,247 AccountId,248 Currency: CurrencyT<AccountId>,249 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,250>(251 Weight,252 Currency::Balance,253 PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,254);255impl<256 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,257 AssetId: Get<MultiLocation>,258 AccountId,259 Currency: CurrencyT<AccountId>,260 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,261 > WeightTrader262 for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>263{264 fn new() -> Self {265 Self(0, Zero::zero(), PhantomData)266 }267268 fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {269 Ok(payment)270 }271}272impl<273 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,274 AssetId: Get<MultiLocation>,275 AccountId,276 Currency: CurrencyT<AccountId>,277 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,278 > Drop279 for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>280{281 fn drop(&mut self) {282 OnUnbalanced::on_unbalanced(Currency::issue(self.1));283 }284}285286parameter_types! {287 pub CheckingAccount: AccountId = PolkadotXcm::check_account();288}289290#[cfg(feature = "foreign-assets")]291pub struct NonZeroIssuance<AccountId, ForeingAssets>(PhantomData<(AccountId, ForeingAssets)>);292293#[cfg(feature = "foreign-assets")]294impl<AccountId, ForeingAssets> Contains<<ForeingAssets as fungibles::Inspect<AccountId>>::AssetId>295 for NonZeroIssuance<AccountId, ForeingAssets>296where297 ForeingAssets: fungibles::Inspect<AccountId>,298{299 fn contains(id: &<ForeingAssets as fungibles::Inspect<AccountId>>::AssetId) -> bool {300 !ForeingAssets::total_issuance(*id).is_zero()301 }302}303304#[cfg(feature = "foreign-assets")]305pub struct AsInnerId<AssetId, ConvertAssetId>(PhantomData<(AssetId, ConvertAssetId)>);306#[cfg(feature = "foreign-assets")]307impl<AssetId: Clone + PartialEq, ConvertAssetId: ConvertXcm<AssetId, AssetId>>308 ConvertXcm<MultiLocation, AssetId> for AsInnerId<AssetId, ConvertAssetId>309where310 AssetId: Borrow<AssetId>,311 AssetId: TryAsForeing<AssetId, ForeignAssetId>,312 AssetIds: Borrow<AssetId>,313{314 fn convert_ref(id: impl Borrow<MultiLocation>) -> Result<AssetId, ()> {315 let id = id.borrow();316317 log::trace!(318 target: "xcm::AsInnerId::Convert",319 "AsInnerId {:?}",320 id321 );322323 let parent = MultiLocation::parent();324 let here = MultiLocation::here();325 let self_location = MultiLocation::new(1, X1(Parachain(ParachainInfo::get().into())));326327 if *id == parent {328 return ConvertAssetId::convert_ref(AssetIds::NativeAssetId(NativeCurrency::Parent));329 }330331 if *id == here || *id == self_location {332 return ConvertAssetId::convert_ref(AssetIds::NativeAssetId(NativeCurrency::Here));333 }334335 match XcmForeignAssetIdMapping::<Runtime>::get_currency_id(id.clone()) {336 Some(AssetIds::ForeignAssetId(foreign_asset_id)) => {337 ConvertAssetId::convert_ref(AssetIds::ForeignAssetId(foreign_asset_id))338 }339 _ => ConvertAssetId::convert_ref(AssetIds::ForeignAssetId(0)),340 }341 }342343 fn reverse_ref(what: impl Borrow<AssetId>) -> Result<MultiLocation, ()> {344 log::trace!(345 target: "xcm::AsInnerId::Reverse",346 "AsInnerId",347 );348349 let asset_id = what.borrow();350351 let parent_id =352 ConvertAssetId::convert_ref(AssetIds::NativeAssetId(NativeCurrency::Parent)).unwrap();353 let here_id =354 ConvertAssetId::convert_ref(AssetIds::NativeAssetId(NativeCurrency::Here)).unwrap();355356 if asset_id.clone() == parent_id {357 return Ok(MultiLocation::parent());358 }359360 if asset_id.clone() == here_id {361 return Ok(MultiLocation::new(362 1,363 X1(Parachain(ParachainInfo::get().into())),364 ));365 }366367 match <AssetId as TryAsForeing<AssetId, ForeignAssetId>>::try_as_foreing(asset_id.clone()) {368 Some(fid) => match XcmForeignAssetIdMapping::<Runtime>::get_multi_location(fid) {369 Some(location) => Ok(location),370 None => Err(()),371 },372 None => Err(()),373 }374 }375}376377378#[cfg(feature = "foreign-assets")]379pub type FungiblesTransactor = FungiblesAdapter<380 381 ForeingAssets,382 383 ConvertedConcreteAssetId<AssetIds, Balance, AsInnerId<AssetIds, JustTry>, JustTry>,384 385 LocationToAccountId,386 387 AccountId,388 389 390 NonZeroIssuance<AccountId, ForeingAssets>,391 392 CheckingAccount,393>;394395396#[cfg(feature = "foreign-assets")]397pub type AssetTransactors = FungiblesTransactor;398399#[cfg(not(feature = "foreign-assets"))]400pub type AssetTransactors = LocalAssetTransactor;401402#[cfg(feature = "foreign-assets")]403pub struct AllAsset;404#[cfg(feature = "foreign-assets")]405impl FilterAssetLocation for AllAsset {406 fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool {407 true408 }409}410411#[cfg(feature = "foreign-assets")]412pub type IsReserve = AllAsset;413#[cfg(not(feature = "foreign-assets"))]414pub type IsReserve = NativeAsset;415416#[cfg(feature = "foreign-assets")]417type Trader<T> = FreeForAll<418 pallet_configuration::WeightToFee<T, Balance>,419 RelayLocation,420 AccountId,421 Balances,422 (),423>;424#[cfg(not(feature = "foreign-assets"))]425type Trader<T> = UsingOnlySelfCurrencyComponents<426 pallet_configuration::WeightToFee<T, Balance>,427 RelayLocation,428 AccountId,429 Balances,430 (),431>;432433pub struct XcmConfig<T>(PhantomData<T>);434impl<T> Config for XcmConfig<T>435where436 T: pallet_configuration::Config,437{438 type Call = Call;439 type XcmSender = XcmRouter;440 441 type AssetTransactor = AssetTransactors;442 type OriginConverter = XcmOriginToTransactDispatchOrigin;443 type IsReserve = IsReserve;444 type IsTeleporter = (); 445 type LocationInverter = LocationInverter<Ancestry>;446 type Barrier = Barrier;447 type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;448 type Trader = Trader<T>;449 type ResponseHandler = (); 450 type SubscriptionService = PolkadotXcm;451452 type AssetTrap = PolkadotXcm;453 type AssetClaims = PolkadotXcm;454}455456impl pallet_xcm::Config for Runtime {457 type Event = Event;458 type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;459 type XcmRouter = XcmRouter;460 type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;461 type XcmExecuteFilter = Everything;462 type XcmExecutor = XcmExecutor<XcmConfig<Self>>;463 type XcmTeleportFilter = Everything;464 type XcmReserveTransferFilter = Everything;465 type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;466 type LocationInverter = LocationInverter<Ancestry>;467 type Origin = Origin;468 type Call = Call;469 const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;470 type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;471}472473impl cumulus_pallet_xcm::Config for Runtime {474 type Event = Event;475 type XcmExecutor = XcmExecutor<XcmConfig<Self>>;476}477478impl cumulus_pallet_xcmp_queue::Config for Runtime {479 type WeightInfo = ();480 type Event = Event;481 type XcmExecutor = XcmExecutor<XcmConfig<Self>>;482 type ChannelInfo = ParachainSystem;483 type VersionWrapper = ();484 type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;485 type ControllerOrigin = EnsureRoot<AccountId>;486 type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;487}488489impl cumulus_pallet_dmp_queue::Config for Runtime {490 type Event = Event;491 type XcmExecutor = XcmExecutor<XcmConfig<Self>>;492 type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;493}