1use core::fmt::Debug;
17use cumulus_primitives_core::ParaId;
18use frame_support::{
19 pallet_prelude::Get,
20 traits::{Contains, ContainsPair},
21};
22use xcm::prelude::*;
23
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 FromNetwork<UniversalLocation, ExpectedNetworkId, L = Location>(
71 core::marker::PhantomData<(UniversalLocation, ExpectedNetworkId, L)>,
72);
73impl<
74 UniversalLocation: Get<InteriorLocation>,
75 ExpectedNetworkId: Get<NetworkId>,
76 L: TryFrom<Location> + TryInto<Location> + Clone + Debug,
77 > ContainsPair<L, L> for FromNetwork<UniversalLocation, ExpectedNetworkId, L>
78{
79 fn contains(a: &L, b: &L) -> bool {
80 tracing::trace!(target: "xcm:contains", ?a, ?b, "FromNetwork");
81 let a = match ((*a).clone().try_into(), (*b).clone().try_into()) {
83 (Ok(a), Ok(b)) if a.starts_with(&b) => a, _ => return false,
85 };
86
87 let universal_source = UniversalLocation::get();
88
89 match ensure_is_remote(universal_source.clone(), a.clone()) {
91 Ok((network_id, _)) => network_id == ExpectedNetworkId::get(),
92 Err(e) => {
93 tracing::debug!(target: "xcm::contains", origin = ?a, ?universal_source, error = ?e, "FromNetwork origin is not remote to the universal_source");
94 false
95 },
96 }
97 }
98}
99
100pub struct RemoteAssetFromLocation<AssetsAllowedNetworks, OriginLocation>(
103 core::marker::PhantomData<(AssetsAllowedNetworks, OriginLocation)>,
104);
105impl<
106 L: TryInto<Location> + Clone,
107 AssetsAllowedNetworks: Contains<Location>,
108 OriginLocation: Get<Location>,
109 > ContainsPair<L, L> for RemoteAssetFromLocation<AssetsAllowedNetworks, OriginLocation>
110{
111 fn contains(asset: &L, origin: &L) -> bool {
112 let Ok(asset) = asset.clone().try_into() else {
113 return false;
114 };
115 let Ok(origin) = origin.clone().try_into() else {
116 return false;
117 };
118 let expected_origin = OriginLocation::get();
119 if !expected_origin.eq(&origin) {
121 tracing::trace!(
122 target: "xcm::contains",
123 ?asset,
124 ?origin,
125 ?expected_origin,
126 "RemoteAssetFromLocation: Asset is not from expected origin"
127 );
128 return false;
129 } else {
130 tracing::trace!(
131 target: "xcm::contains",
132 ?asset,
133 ?origin,
134 "RemoteAssetFromLocation",
135 );
136 }
137
138 AssetsAllowedNetworks::contains(&asset)
140 }
141}
142impl<AssetsAllowedNetworks: Contains<Location>, OriginLocation: Get<Location>>
143 ContainsPair<Asset, Location> for RemoteAssetFromLocation<AssetsAllowedNetworks, OriginLocation>
144{
145 fn contains(asset: &Asset, origin: &Location) -> bool {
146 tracing::trace!(target: "xcm:contains", ?asset, ?origin, "RemoteAssetFromLocation");
147 <Self as ContainsPair<Location, Location>>::contains(&asset.id.0, origin)
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154 use frame_support::parameter_types;
155 use xcm::latest::{ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH};
156
157 parameter_types! {
158 pub UniversalLocation: InteriorLocation = [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(1000)].into();
159 pub ExpectedNetworkId: NetworkId = ByGenesis(WESTEND_GENESIS_HASH);
160 }
161
162 #[test]
163 fn from_network_contains_works() {
164 let asset: Location = (
166 Parent,
167 Parent,
168 GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
169 Parachain(1000),
170 PalletInstance(1),
171 GeneralIndex(1),
172 )
173 .into();
174 let origin: Location =
175 (Parent, Parent, GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000))
176 .into();
177 assert!(FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
178
179 let asset: Location = (
181 Parent,
182 Parent,
183 GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)),
184 Parachain(1000),
185 PalletInstance(1),
186 GeneralIndex(1),
187 )
188 .into();
189 let origin: Location =
190 (Parent, Parent, GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(1000))
191 .into();
192 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
193
194 let asset: Location = (PalletInstance(1), GeneralIndex(1)).into();
196 let origin: Location = Here.into();
197 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
198
199 let asset: Location = (
201 Parent,
202 Parent,
203 GlobalConsensus(Polkadot),
204 Parachain(1000),
205 PalletInstance(1),
206 GeneralIndex(1),
207 )
208 .into();
209 let origin: Location =
210 (Parent, Parent, GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000))
211 .into();
212 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
213
214 let asset: Location = (
216 Parent,
217 Parent,
218 GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
219 Parachain(1000),
220 PalletInstance(1),
221 GeneralIndex(1),
222 )
223 .into();
224 let origin: Location = (Parent, Parent, GlobalConsensus(Polkadot), Parachain(1000)).into();
225 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
226
227 let asset: Location = (
229 Parent,
230 Parent,
231 GlobalConsensus(Polkadot),
232 Parachain(1000),
233 PalletInstance(1),
234 GeneralIndex(1),
235 )
236 .into();
237 let origin: Location = (Parent, Parent, GlobalConsensus(Polkadot), Parachain(1000)).into();
238 assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
239 }
240}