1use crate::impls::AccountIdOf;
17use core::marker::PhantomData;
18use cumulus_primitives_core::{IsSystem, ParaId};
19use frame_support::{
20 traits::{fungibles::Inspect, tokens::ConversionToAssetBalance, Contains, ContainsPair},
21 weights::Weight,
22};
23use sp_runtime::traits::Get;
24use xcm::latest::prelude::*;
25
26pub struct AssetFeeAsExistentialDepositMultiplier<
30 Runtime,
31 WeightToFee,
32 BalanceConverter,
33 AssetInstance: 'static,
34>(PhantomData<(Runtime, WeightToFee, BalanceConverter, AssetInstance)>);
35impl<CurrencyBalance, Runtime, WeightToFee, BalanceConverter, AssetInstance>
36 cumulus_primitives_utility::ChargeWeightInFungibles<
37 AccountIdOf<Runtime>,
38 pallet_assets::Pallet<Runtime, AssetInstance>,
39 > for AssetFeeAsExistentialDepositMultiplier<Runtime, WeightToFee, BalanceConverter, AssetInstance>
40where
41 Runtime: pallet_assets::Config<AssetInstance>,
42 WeightToFee: frame_support::weights::WeightToFee<Balance = CurrencyBalance>,
43 BalanceConverter: ConversionToAssetBalance<
44 CurrencyBalance,
45 <Runtime as pallet_assets::Config<AssetInstance>>::AssetId,
46 <Runtime as pallet_assets::Config<AssetInstance>>::Balance,
47 >,
48 <BalanceConverter as ConversionToAssetBalance<
49 CurrencyBalance,
50 <Runtime as pallet_assets::Config<AssetInstance>>::AssetId,
51 <Runtime as pallet_assets::Config<AssetInstance>>::Balance,
52 >>::Error: core::fmt::Debug,
53{
54 fn charge_weight_in_fungibles(
55 asset_id: <pallet_assets::Pallet<Runtime, AssetInstance> as Inspect<
56 AccountIdOf<Runtime>,
57 >>::AssetId,
58 weight: Weight,
59 ) -> Result<
60 <pallet_assets::Pallet<Runtime, AssetInstance> as Inspect<AccountIdOf<Runtime>>>::Balance,
61 XcmError,
62 > {
63 let amount = WeightToFee::weight_to_fee(&weight);
64 let asset_amount = BalanceConverter::to_asset_balance(amount, asset_id)
67 .map_err(|error| {
68 tracing::debug!(target: "xcm::charge_weight_in_fungibles", ?error, "AssetFeeAsExistentialDepositMultiplier cannot convert to valid balance (possibly below ED)");
69 XcmError::TooExpensive
70 })?;
71 Ok(asset_amount)
72 }
73}
74
75pub struct ConcreteNativeAssetFrom<LocationValue>(PhantomData<LocationValue>);
77impl<LocationValue: Get<Location>> ContainsPair<Asset, Location>
78 for ConcreteNativeAssetFrom<LocationValue>
79{
80 fn contains(asset: &Asset, origin: &Location) -> bool {
81 tracing::trace!(
82 target: "xcm::filter_asset_location",
83 ?asset, ?origin, location=?LocationValue::get(),
84 "ConcreteNativeAsset"
85 );
86 asset.id.0 == *origin && origin == &LocationValue::get()
87 }
88}
89
90pub struct RelayOrOtherSystemParachains<
91 SystemParachainMatcher: Contains<Location>,
92 Runtime: parachain_info::Config,
93> {
94 _runtime: PhantomData<(SystemParachainMatcher, Runtime)>,
95}
96impl<SystemParachainMatcher: Contains<Location>, Runtime: parachain_info::Config> Contains<Location>
97 for RelayOrOtherSystemParachains<SystemParachainMatcher, Runtime>
98{
99 fn contains(l: &Location) -> bool {
100 let self_para_id: u32 = parachain_info::Pallet::<Runtime>::get().into();
101 if let (0, [Parachain(para_id)]) = l.unpack() {
102 if *para_id == self_para_id {
103 return false
104 }
105 }
106 matches!(l.unpack(), (1, [])) || SystemParachainMatcher::contains(l)
107 }
108}
109
110pub struct AllSiblingSystemParachains;
115impl Contains<Location> for AllSiblingSystemParachains {
116 fn contains(l: &Location) -> bool {
117 tracing::trace!(target: "xcm::contains", location=?l, "AllSiblingSystemParachains");
118 match l.unpack() {
119 (1, [Parachain(id)]) => ParaId::from(*id).is_system(),
121 _ => false,
123 }
124 }
125}
126
127pub struct ConcreteAssetFromSystem<AssetLocation>(PhantomData<AssetLocation>);
129impl<AssetLocation: Get<Location>> ContainsPair<Asset, Location>
130 for ConcreteAssetFromSystem<AssetLocation>
131{
132 fn contains(asset: &Asset, origin: &Location) -> bool {
133 tracing::trace!(target: "xcm::contains", ?asset, ?origin, "ConcreteAssetFromSystem");
134 let is_system = match origin.unpack() {
135 (1, []) => true,
137 (1, [Parachain(id)]) => ParaId::from(*id).is_system(),
139 _ => false,
141 };
142 asset.id.0 == AssetLocation::get() && is_system
143 }
144}
145
146pub struct ParentRelayOrSiblingParachains;
151impl Contains<Location> for ParentRelayOrSiblingParachains {
152 fn contains(location: &Location) -> bool {
153 matches!(location.unpack(), (1, []) | (1, [Parachain(_)]))
154 }
155}
156
157pub struct AliasAccountId32FromSiblingSystemChain;
163impl ContainsPair<Location, Location> for AliasAccountId32FromSiblingSystemChain {
164 fn contains(origin: &Location, target: &Location) -> bool {
165 let result = match origin.unpack() {
166 (1, [Parachain(para_id), AccountId32 { network: _, id: origin }])
168 if ParaId::from(*para_id).is_system() =>
169 {
170 match target.unpack() {
171 (0, [AccountId32 { network: _, id: target }]) => target.eq(origin),
173 _ => false,
174 }
175 },
176 _ => false,
177 };
178 tracing::trace!(
179 target: "xcm::contains",
180 ?origin, ?target, ?result,
181 "AliasAccountId32FromSiblingSystemChain"
182 );
183 result
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use frame_support::{parameter_types, traits::Contains};
190
191 use super::{
192 AliasAccountId32FromSiblingSystemChain, AllSiblingSystemParachains, Asset,
193 ConcreteAssetFromSystem, ContainsPair, GeneralIndex, Here, Location, PalletInstance,
194 Parachain, Parent,
195 };
196 use polkadot_primitives::LOWEST_PUBLIC_ID;
197 use xcm::latest::prelude::*;
198
199 parameter_types! {
200 pub const RelayLocation: Location = Location::parent();
201 }
202
203 #[test]
204 fn concrete_asset_from_relay_works() {
205 let expected_asset: Asset = (Parent, 1000000).into();
206 let expected_origin: Location = (Parent, Here).into();
207
208 assert!(<ConcreteAssetFromSystem<RelayLocation>>::contains(
209 &expected_asset,
210 &expected_origin
211 ));
212 }
213
214 #[test]
215 fn concrete_asset_from_sibling_system_para_fails_for_wrong_asset() {
216 let unexpected_assets: Vec<Asset> = vec![
217 (Here, 1000000).into(),
218 ((PalletInstance(50), GeneralIndex(1)), 1000000).into(),
219 ((Parent, Parachain(1000), PalletInstance(50), GeneralIndex(1)), 1000000).into(),
220 ];
221 let expected_origin: Location = (Parent, Parachain(1000)).into();
222
223 unexpected_assets.iter().for_each(|asset| {
224 assert!(!<ConcreteAssetFromSystem<RelayLocation>>::contains(asset, &expected_origin));
225 });
226 }
227
228 #[test]
229 fn concrete_asset_from_sibling_system_para_works_for_correct_asset() {
230 let test_data = vec![
232 (0, true),
233 (1, true),
234 (1000, true),
235 (1999, true),
236 (2000, false), (2001, false), ];
239
240 let expected_asset: Asset = (Parent, 1000000).into();
241
242 for (para_id, expected_result) in test_data {
243 let origin: Location = (Parent, Parachain(para_id)).into();
244 assert_eq!(
245 expected_result,
246 <ConcreteAssetFromSystem<RelayLocation>>::contains(&expected_asset, &origin)
247 );
248 }
249 }
250
251 #[test]
252 fn all_sibling_system_parachains_works() {
253 assert!(AllSiblingSystemParachains::contains(&Location::new(1, [Parachain(1)])));
255 assert!(!AllSiblingSystemParachains::contains(&Location::new(
257 1,
258 [Parachain(LOWEST_PUBLIC_ID.into())]
259 )));
260 assert!(!AllSiblingSystemParachains::contains(&Location::new(0, [Parachain(1)])));
262 assert!(!AllSiblingSystemParachains::contains(&Location::new(1, [OnlyChild])));
264 }
265
266 #[test]
267 fn alias_accountid32_from_sibling_system_parachains() {
268 let acc_42 = AccountId32 { network: None, id: [42u8; 32] };
269 let acc_13 = AccountId32 { network: None, id: [13u8; 32] };
270 assert!(AliasAccountId32FromSiblingSystemChain::contains(
272 &Location::new(1, [Parachain(1), acc_42]),
273 &Location::new(0, [acc_42])
274 ));
275 assert!(!AliasAccountId32FromSiblingSystemChain::contains(
277 &Location::new(1, [Parachain(1), acc_42]),
278 &Location::new(0, [])
279 ));
280 assert!(!AliasAccountId32FromSiblingSystemChain::contains(
281 &Location::new(1, [Parachain(1), acc_42]),
282 &Location::new(0, [Parachain(1)])
283 ));
284 assert!(!AliasAccountId32FromSiblingSystemChain::contains(
285 &Location::new(1, [Parachain(1), acc_42]),
286 &Location::new(0, [GeneralIndex(42)])
287 ));
288 assert!(!AliasAccountId32FromSiblingSystemChain::contains(
289 &Location::new(1, [Parachain(1), acc_42]),
290 &Location::new(1, [acc_42])
291 ));
292 assert!(!AliasAccountId32FromSiblingSystemChain::contains(
293 &Location::new(1, [Parachain(1), acc_42]),
294 &Location::new(2, [acc_42])
295 ));
296 assert!(!AliasAccountId32FromSiblingSystemChain::contains(
298 &Location::new(1, [Parachain(1), acc_13]),
299 &Location::new(0, [acc_42])
300 ));
301 assert!(!AliasAccountId32FromSiblingSystemChain::contains(
303 &Location::new(1, [Parachain(LOWEST_PUBLIC_ID.into()), acc_42]),
304 &Location::new(0, [acc_42])
305 ));
306 assert!(!AliasAccountId32FromSiblingSystemChain::contains(
307 &Location::new(0, [acc_13]),
308 &Location::new(0, [acc_13]),
309 ));
310 assert!(!AliasAccountId32FromSiblingSystemChain::contains(
311 &Location::new(0, [acc_42]),
312 &Location::new(1, [Parachain(1), acc_42]),
313 ));
314 }
315}