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 },
64 _ => false,
65 }
66 }
67}
68
69pub struct TeleportableAssetWithTrustedReserve<SelfParaId, ReserveProvider, L = Location>(
72 core::marker::PhantomData<(SelfParaId, ReserveProvider, L)>,
73);
74impl<
75 SelfParaId: Get<ParaId>,
76 L: TryFrom<Location> + TryInto<Location> + Clone + Debug,
77 ReserveProvider: ProvideAssetReserves<Location, ForeignAssetReserveData>,
78 > ContainsPair<L, L> for TeleportableAssetWithTrustedReserve<SelfParaId, ReserveProvider, L>
79{
80 fn contains(a: &L, b: &L) -> bool {
81 tracing::trace!(target: "xcm::contains", ?a, ?b, "TeleportableAssetWithTrustedReserve");
82 let (a, b) = match ((*a).clone().try_into(), (*b).clone().try_into()) {
84 (Ok(a), Ok(b)) => (a, b),
85 _ => return false,
86 };
87 let reserves = ReserveProvider::reserves(&a);
88 tracing::trace!(target: "xcm::contains", ?reserves, "TeleportableAssetWithTrustedReserve");
89 let filter = (b, true).into();
91 reserves.contains(&filter)
92 }
93}
94
95pub struct NonTeleportableAssetFromTrustedReserve<SelfParaId, ReserveProvider, L = Location>(
99 core::marker::PhantomData<(SelfParaId, ReserveProvider, L)>,
100);
101impl<
102 SelfParaId: Get<ParaId>,
103 L: TryFrom<Location> + TryInto<Location> + Clone + Debug,
104 ReserveProvider: ProvideAssetReserves<Location, ForeignAssetReserveData>,
105 > ContainsPair<L, L> for NonTeleportableAssetFromTrustedReserve<SelfParaId, ReserveProvider, L>
106{
107 fn contains(a: &L, b: &L) -> bool {
108 tracing::trace!(target: "xcm::contains", ?a, ?b, "NonTeleportableAssetFromTrustedReserve");
109 let (a, b) = match ((*a).clone().try_into(), (*b).clone().try_into()) {
111 (Ok(a), Ok(b)) => (a, b),
112 _ => return false,
113 };
114 let reserves = ReserveProvider::reserves(&a);
115 tracing::trace!(target: "xcm::contains", ?reserves, "NonTeleportableAssetFromTrustedReserve");
116 let filter = (b, false).into();
118 reserves.contains(&filter)
119 }
120}
121
122pub struct FromNetwork<UniversalLocation, ExpectedNetworkId, L = Location>(
125 core::marker::PhantomData<(UniversalLocation, ExpectedNetworkId, L)>,
126);
127impl<
128 UniversalLocation: Get<InteriorLocation>,
129 ExpectedNetworkId: Get<NetworkId>,
130 L: TryFrom<Location> + TryInto<Location> + Clone + Debug,
131 > ContainsPair<L, L> for FromNetwork<UniversalLocation, ExpectedNetworkId, L>
132{
133 fn contains(a: &L, b: &L) -> bool {
134 tracing::trace!(target: "xcm:contains", ?a, ?b, "FromNetwork");
135 let a = match ((*a).clone().try_into(), (*b).clone().try_into()) {
137 (Ok(a), Ok(b)) if a.starts_with(&b) => a, _ => return false,
139 };
140
141 let universal_source = UniversalLocation::get();
142
143 match ensure_is_remote(universal_source.clone(), a.clone()) {
145 Ok((network_id, _)) => network_id == ExpectedNetworkId::get(),
146 Err(e) => {
147 tracing::debug!(target: "xcm::contains", origin = ?a, ?universal_source, error = ?e, "FromNetwork origin is not remote to the universal_source");
148 false
149 },
150 }
151 }
152}
153
154pub struct RemoteAssetFromLocation<AssetsAllowedNetworks, OriginLocation>(
157 core::marker::PhantomData<(AssetsAllowedNetworks, OriginLocation)>,
158);
159impl<
160 L: TryInto<Location> + Clone,
161 AssetsAllowedNetworks: Contains<Location>,
162 OriginLocation: Get<Location>,
163 > ContainsPair<L, L> for RemoteAssetFromLocation<AssetsAllowedNetworks, OriginLocation>
164{
165 fn contains(asset: &L, origin: &L) -> bool {
166 let Ok(asset) = asset.clone().try_into() else {
167 return false;
168 };
169 let Ok(origin) = origin.clone().try_into() else {
170 return false;
171 };
172 let expected_origin = OriginLocation::get();
173 if !expected_origin.eq(&origin) {
175 tracing::trace!(
176 target: "xcm::contains",
177 ?asset,
178 ?origin,
179 ?expected_origin,
180 "RemoteAssetFromLocation: Asset is not from expected origin"
181 );
182 return false;
183 } else {
184 tracing::trace!(
185 target: "xcm::contains",
186 ?asset,
187 ?origin,
188 "RemoteAssetFromLocation",
189 );
190 }
191
192 AssetsAllowedNetworks::contains(&asset)
194 }
195}
196impl<AssetsAllowedNetworks: Contains<Location>, OriginLocation: Get<Location>>
197 ContainsPair<Asset, Location> for RemoteAssetFromLocation<AssetsAllowedNetworks, OriginLocation>
198{
199 fn contains(asset: &Asset, origin: &Location) -> bool {
200 tracing::trace!(target: "xcm:contains", ?asset, ?origin, "RemoteAssetFromLocation");
201 <Self as ContainsPair<Location, Location>>::contains(&asset.id.0, origin)
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208 use frame_support::parameter_types;
209 use xcm::latest::{ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH};
210
211 parameter_types! {
212 pub UniversalLocation: InteriorLocation = [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(1000)].into();
213 pub ExpectedNetworkId: NetworkId = ByGenesis(WESTEND_GENESIS_HASH);
214 }
215
216 #[test]
217 fn from_network_contains_works() {
218 let asset: Location = (
220 Parent,
221 Parent,
222 GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
223 Parachain(1000),
224 PalletInstance(1),
225 GeneralIndex(1),
226 )
227 .into();
228 let origin: Location =
229 (Parent, Parent, GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000))
230 .into();
231 assert!(FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
232
233 let asset: Location = (
235 Parent,
236 Parent,
237 GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)),
238 Parachain(1000),
239 PalletInstance(1),
240 GeneralIndex(1),
241 )
242 .into();
243 let origin: Location =
244 (Parent, Parent, GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(1000))
245 .into();
246 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
247
248 let asset: Location = (PalletInstance(1), GeneralIndex(1)).into();
250 let origin: Location = Here.into();
251 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
252
253 let asset: Location = (
255 Parent,
256 Parent,
257 GlobalConsensus(Polkadot),
258 Parachain(1000),
259 PalletInstance(1),
260 GeneralIndex(1),
261 )
262 .into();
263 let origin: Location =
264 (Parent, Parent, GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000))
265 .into();
266 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
267
268 let asset: Location = (
270 Parent,
271 Parent,
272 GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
273 Parachain(1000),
274 PalletInstance(1),
275 GeneralIndex(1),
276 )
277 .into();
278 let origin: Location = (Parent, Parent, GlobalConsensus(Polkadot), Parachain(1000)).into();
279 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
280
281 let asset: Location = (
283 Parent,
284 Parent,
285 GlobalConsensus(Polkadot),
286 Parachain(1000),
287 PalletInstance(1),
288 GeneralIndex(1),
289 )
290 .into();
291 let origin: Location = (Parent, Parent, GlobalConsensus(Polkadot), Parachain(1000)).into();
292 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
293 }
294}