1use crate::local_and_foreign_assets::ForeignAssetReserveData;
17use core::fmt::Debug;
18use cumulus_primitives_core::ParaId;
19use frame_support::{
20 pallet_prelude::Get,
21 traits::{tokens::ProvideAssetReserves, Contains, ContainsPair},
22};
23use xcm::prelude::*;
24use xcm_builder::ensure_is_remote;
25
26frame_support::parameter_types! {
27 pub LocalLocationPattern: Location = Location::new(0, Here);
28 pub ParentLocation: Location = Location::parent();
29}
30
31pub struct IsForeignConcreteAsset<IsForeign>(core::marker::PhantomData<IsForeign>);
33impl<IsForeign: ContainsPair<Location, Location>> ContainsPair<Asset, Location>
34 for IsForeignConcreteAsset<IsForeign>
35{
36 fn contains(asset: &Asset, origin: &Location) -> bool {
37 let result = matches!(asset.id, AssetId(ref id) if IsForeign::contains(id, origin));
38 tracing::trace!(target: "xcm::contains", ?asset, ?origin, ?result, "IsForeignConcreteAsset");
39 result
40 }
41}
42
43pub struct FromSiblingParachain<SelfParaId, L = Location>(
46 core::marker::PhantomData<(SelfParaId, L)>,
47);
48impl<SelfParaId: Get<ParaId>, L: TryFrom<Location> + TryInto<Location> + Clone + Debug>
49 ContainsPair<L, L> for FromSiblingParachain<SelfParaId, L>
50{
51 fn contains(a: &L, b: &L) -> bool {
52 tracing::trace!(target: "xcm:contains", ?a, ?b, "FromSiblingParachain");
53 let a = match ((*a).clone().try_into(), (*b).clone().try_into()) {
55 (Ok(a), Ok(b)) if a.starts_with(&b) => a, _ => return false,
57 };
58
59 match a.unpack() {
61 (1, interior) =>
62 matches!(interior.first(), Some(Parachain(sibling_para_id)) if sibling_para_id.ne(&u32::from(SelfParaId::get()))),
63 _ => false,
64 }
65 }
66}
67
68pub struct TeleportableAssetWithTrustedReserve<SelfParaId, ReserveProvider, L = Location>(
71 core::marker::PhantomData<(SelfParaId, ReserveProvider, L)>,
72);
73impl<
74 SelfParaId: Get<ParaId>,
75 L: TryFrom<Location> + TryInto<Location> + Clone + Debug,
76 ReserveProvider: ProvideAssetReserves<Location, ForeignAssetReserveData>,
77 > ContainsPair<L, L> for TeleportableAssetWithTrustedReserve<SelfParaId, ReserveProvider, L>
78{
79 fn contains(a: &L, b: &L) -> bool {
80 tracing::trace!(target: "xcm::contains", ?a, ?b, "TeleportableAssetWithTrustedReserve");
81 let (a, b) = match ((*a).clone().try_into(), (*b).clone().try_into()) {
83 (Ok(a), Ok(b)) => (a, b),
84 _ => return false,
85 };
86 let reserves = ReserveProvider::reserves(&a);
87 tracing::trace!(target: "xcm::contains", ?reserves, "TeleportableAssetWithTrustedReserve");
88 let filter = (b, true).into();
90 reserves.contains(&filter)
91 }
92}
93
94pub struct NonTeleportableAssetFromTrustedReserve<SelfParaId, ReserveProvider, L = Location>(
98 core::marker::PhantomData<(SelfParaId, ReserveProvider, L)>,
99);
100impl<
101 SelfParaId: Get<ParaId>,
102 L: TryFrom<Location> + TryInto<Location> + Clone + Debug,
103 ReserveProvider: ProvideAssetReserves<Location, ForeignAssetReserveData>,
104 > ContainsPair<L, L> for NonTeleportableAssetFromTrustedReserve<SelfParaId, ReserveProvider, L>
105{
106 fn contains(a: &L, b: &L) -> bool {
107 tracing::trace!(target: "xcm::contains", ?a, ?b, "NonTeleportableAssetFromTrustedReserve");
108 let (a, b) = match ((*a).clone().try_into(), (*b).clone().try_into()) {
110 (Ok(a), Ok(b)) => (a, b),
111 _ => return false,
112 };
113 let reserves = ReserveProvider::reserves(&a);
114 tracing::trace!(target: "xcm::contains", ?reserves, "NonTeleportableAssetFromTrustedReserve");
115 let filter = (b, false).into();
117 reserves.contains(&filter)
118 }
119}
120
121pub struct FromNetwork<UniversalLocation, ExpectedNetworkId, L = Location>(
124 core::marker::PhantomData<(UniversalLocation, ExpectedNetworkId, L)>,
125);
126impl<
127 UniversalLocation: Get<InteriorLocation>,
128 ExpectedNetworkId: Get<NetworkId>,
129 L: TryFrom<Location> + TryInto<Location> + Clone + Debug,
130 > ContainsPair<L, L> for FromNetwork<UniversalLocation, ExpectedNetworkId, L>
131{
132 fn contains(a: &L, b: &L) -> bool {
133 tracing::trace!(target: "xcm:contains", ?a, ?b, "FromNetwork");
134 let a = match ((*a).clone().try_into(), (*b).clone().try_into()) {
136 (Ok(a), Ok(b)) if a.starts_with(&b) => a, _ => return false,
138 };
139
140 let universal_source = UniversalLocation::get();
141
142 match ensure_is_remote(universal_source.clone(), a.clone()) {
144 Ok((network_id, _)) => network_id == ExpectedNetworkId::get(),
145 Err(e) => {
146 tracing::debug!(target: "xcm::contains", origin = ?a, ?universal_source, error = ?e, "FromNetwork origin is not remote to the universal_source");
147 false
148 },
149 }
150 }
151}
152
153pub struct RemoteAssetFromLocation<AssetsAllowedNetworks, OriginLocation>(
156 core::marker::PhantomData<(AssetsAllowedNetworks, OriginLocation)>,
157);
158impl<
159 L: TryInto<Location> + Clone,
160 AssetsAllowedNetworks: Contains<Location>,
161 OriginLocation: Get<Location>,
162 > ContainsPair<L, L> for RemoteAssetFromLocation<AssetsAllowedNetworks, OriginLocation>
163{
164 fn contains(asset: &L, origin: &L) -> bool {
165 let Ok(asset) = asset.clone().try_into() else {
166 return false;
167 };
168 let Ok(origin) = origin.clone().try_into() else {
169 return false;
170 };
171 let expected_origin = OriginLocation::get();
172 if !expected_origin.eq(&origin) {
174 tracing::trace!(
175 target: "xcm::contains",
176 ?asset,
177 ?origin,
178 ?expected_origin,
179 "RemoteAssetFromLocation: Asset is not from expected origin"
180 );
181 return false;
182 } else {
183 tracing::trace!(
184 target: "xcm::contains",
185 ?asset,
186 ?origin,
187 "RemoteAssetFromLocation",
188 );
189 }
190
191 AssetsAllowedNetworks::contains(&asset)
193 }
194}
195impl<AssetsAllowedNetworks: Contains<Location>, OriginLocation: Get<Location>>
196 ContainsPair<Asset, Location> for RemoteAssetFromLocation<AssetsAllowedNetworks, OriginLocation>
197{
198 fn contains(asset: &Asset, origin: &Location) -> bool {
199 tracing::trace!(target: "xcm:contains", ?asset, ?origin, "RemoteAssetFromLocation");
200 <Self as ContainsPair<Location, Location>>::contains(&asset.id.0, origin)
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207 use frame_support::parameter_types;
208 use xcm::latest::{ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH};
209
210 parameter_types! {
211 pub UniversalLocation: InteriorLocation = [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(1000)].into();
212 pub ExpectedNetworkId: NetworkId = ByGenesis(WESTEND_GENESIS_HASH);
213 }
214
215 #[test]
216 fn from_network_contains_works() {
217 let asset: Location = (
219 Parent,
220 Parent,
221 GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
222 Parachain(1000),
223 PalletInstance(1),
224 GeneralIndex(1),
225 )
226 .into();
227 let origin: Location =
228 (Parent, Parent, GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000))
229 .into();
230 assert!(FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
231
232 let asset: Location = (
234 Parent,
235 Parent,
236 GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)),
237 Parachain(1000),
238 PalletInstance(1),
239 GeneralIndex(1),
240 )
241 .into();
242 let origin: Location =
243 (Parent, Parent, GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(1000))
244 .into();
245 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
246
247 let asset: Location = (PalletInstance(1), GeneralIndex(1)).into();
249 let origin: Location = Here.into();
250 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
251
252 let asset: Location = (
254 Parent,
255 Parent,
256 GlobalConsensus(Polkadot),
257 Parachain(1000),
258 PalletInstance(1),
259 GeneralIndex(1),
260 )
261 .into();
262 let origin: Location =
263 (Parent, Parent, GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000))
264 .into();
265 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
266
267 let asset: Location = (
269 Parent,
270 Parent,
271 GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
272 Parachain(1000),
273 PalletInstance(1),
274 GeneralIndex(1),
275 )
276 .into();
277 let origin: Location = (Parent, Parent, GlobalConsensus(Polkadot), Parachain(1000)).into();
278 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
279
280 let asset: Location = (
282 Parent,
283 Parent,
284 GlobalConsensus(Polkadot),
285 Parachain(1000),
286 PalletInstance(1),
287 GeneralIndex(1),
288 )
289 .into();
290 let origin: Location = (Parent, Parent, GlobalConsensus(Polkadot), Parachain(1000)).into();
291 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
292 }
293}