1#![cfg_attr(not(feature = "std"), no_std)]
17
18#[cfg(feature = "runtime-benchmarks")]
19pub mod benchmarks;
20mod erc20_transactor;
21pub mod foreign_creators;
22pub mod fungible_conversion;
23pub mod local_and_foreign_assets;
24pub mod matching;
25pub mod migrations;
26pub mod runtime_api;
27
28pub use erc20_transactor::ERC20Transactor;
29
30extern crate alloc;
31extern crate core;
32
33use crate::matching::{LocalLocationPattern, ParentLocation};
34use alloc::vec::Vec;
35use codec::{Decode, EncodeLike};
36use core::{cmp::PartialEq, marker::PhantomData};
37use pezframe_support::traits::{Contains, Equals, EverythingBut};
38use pezsp_core::H160;
39use pezsp_runtime::traits::{MaybeEquivalence, TryConvertInto};
40use teyrchains_common::{AssetIdForTrustBackedAssets, CollectionId, ItemId};
41use xcm::prelude::*;
42use xcm_builder::{
43 AsPrefixedGeneralIndex, MatchedConvertedConcreteId, StartsWith, WithLatestLocationConverter,
44};
45use xcm_executor::traits::JustTry;
46
47pub type AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation, L = Location> =
49 AsPrefixedGeneralIndex<
50 TrustBackedAssetsPalletLocation,
51 AssetIdForTrustBackedAssets,
52 TryConvertInto,
53 L,
54 >;
55
56pub type CollectionIdForUniquesConvert<UniquesPalletLocation> =
58 AsPrefixedGeneralIndex<UniquesPalletLocation, CollectionId, TryConvertInto>;
59
60pub type TrustBackedAssetsConvertedConcreteId<
62 TrustBackedAssetsPalletLocation,
63 Balance,
64 L = Location,
65> = MatchedConvertedConcreteId<
66 AssetIdForTrustBackedAssets,
67 Balance,
68 StartsWith<TrustBackedAssetsPalletLocation>,
69 AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation, L>,
70 TryConvertInto,
71>;
72
73pub type UniquesConvertedConcreteId<UniquesPalletLocation> = MatchedConvertedConcreteId<
75 CollectionId,
76 ItemId,
77 StartsWith<UniquesPalletLocation>,
80 CollectionIdForUniquesConvert<UniquesPalletLocation>,
81 TryConvertInto,
82>;
83
84pub type TrustBackedAssetsAsLocation<
89 TrustBackedAssetsPalletLocation,
90 Balance,
91 L,
92 LocationConverter = WithLatestLocationConverter<L>,
93> = MatchedConvertedConcreteId<
94 L,
95 Balance,
96 StartsWith<TrustBackedAssetsPalletLocation>,
97 LocationConverter,
98 TryConvertInto,
99>;
100
101pub type ForeignAssetsConvertedConcreteId<
110 AdditionalLocationExclusionFilter,
111 Balance,
112 AssetId,
113 LocationToAssetIdConverter = WithLatestLocationConverter<AssetId>,
114 BalanceConverter = TryConvertInto,
115> = MatchedConvertedConcreteId<
116 AssetId,
117 Balance,
118 EverythingBut<(
119 Equals<ParentLocation>,
121 StartsWith<LocalLocationPattern>,
126 AdditionalLocationExclusionFilter,
128 )>,
129 LocationToAssetIdConverter,
130 BalanceConverter,
131>;
132
133pub struct IsLocalAccountKey20;
136impl Contains<Location> for IsLocalAccountKey20 {
137 fn contains(location: &Location) -> bool {
138 matches!(location.unpack(), (0, [AccountKey20 { .. }]))
139 }
140}
141
142pub struct AccountKey20ToH160;
145impl MaybeEquivalence<Location, H160> for AccountKey20ToH160 {
146 fn convert(location: &Location) -> Option<H160> {
147 match location.unpack() {
148 (0, [AccountKey20 { key, .. }]) => Some((*key).into()),
149 _ => None,
150 }
151 }
152
153 fn convert_back(key: &H160) -> Option<Location> {
154 Some(Location::new(0, [AccountKey20 { key: (*key).into(), network: None }]))
155 }
156}
157
158pub type ERC20Matcher =
161 MatchedConvertedConcreteId<H160, u128, IsLocalAccountKey20, AccountKey20ToH160, JustTry>;
162
163pub type AssetIdForPoolAssets = u32;
164
165pub type AssetIdForPoolAssetsConvert<PoolAssetsPalletLocation, L = Location> =
167 AsPrefixedGeneralIndex<PoolAssetsPalletLocation, AssetIdForPoolAssets, TryConvertInto, L>;
168pub type PoolAssetsConvertedConcreteId<PoolAssetsPalletLocation, Balance> =
170 MatchedConvertedConcreteId<
171 AssetIdForPoolAssets,
172 Balance,
173 StartsWith<PoolAssetsPalletLocation>,
174 AssetIdForPoolAssetsConvert<PoolAssetsPalletLocation>,
175 TryConvertInto,
176 >;
177
178pub struct PoolAdapter<Runtime>(PhantomData<Runtime>);
181impl<
182 Runtime: pezpallet_asset_conversion::Config<PoolId = (L, L), AssetKind = L>,
183 L: TryFrom<Location> + TryInto<Location> + Clone + Decode + EncodeLike + PartialEq,
184 > PoolAdapter<Runtime>
185{
186 pub fn get_assets_in_pool_with(asset: Location) -> Result<Vec<AssetId>, ()> {
197 let asset: L = asset.try_into().map_err(|_| ())?;
199 Self::iter_assets_in_pool_with(&asset)
200 .map(|location| {
201 location.try_into().map_err(|_| ()).map(AssetId)
203 })
204 .collect::<Result<Vec<_>, _>>()
205 }
206
207 pub fn quote_price_tokens_for_exact_tokens(
213 asset_1: Location,
214 asset_2: Location,
215 amount: Runtime::Balance,
216 include_fees: bool,
217 ) -> Result<Option<Runtime::Balance>, ()> {
218 let asset_1: L = asset_1.try_into().map_err(|_| ())?;
220 let asset_2: L = asset_2.try_into().map_err(|_| ())?;
221
222 Ok(pezpallet_asset_conversion::Pezpallet::<Runtime>::quote_price_tokens_for_exact_tokens(
224 asset_1,
225 asset_2,
226 amount,
227 include_fees,
228 ))
229 }
230
231 pub fn iter_assets_in_pool_with(asset: &L) -> impl Iterator<Item = L> + '_ {
233 pezpallet_asset_conversion::Pools::<Runtime>::iter_keys().filter_map(
234 |(asset_1, asset_2)| {
235 if asset_1 == *asset {
236 Some(asset_2)
237 } else if asset_2 == *asset {
238 Some(asset_1)
239 } else {
240 None
241 }
242 },
243 )
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250 use pezsp_runtime::traits::MaybeEquivalence;
251 use xcm_builder::{StartsWithExplicitGlobalConsensus, WithLatestLocationConverter};
252 use xcm_executor::traits::{Error as MatchError, MatchesFungibles};
253
254 #[test]
255 fn asset_id_for_trust_backed_assets_convert_works() {
256 pezframe_support::parameter_types! {
257 pub TrustBackedAssetsPalletLocation: Location = Location::new(5, [PalletInstance(13)]);
258 }
259 let local_asset_id = 123456789 as AssetIdForTrustBackedAssets;
260 let expected_reverse_ref =
261 Location::new(5, [PalletInstance(13), GeneralIndex(local_asset_id.into())]);
262
263 assert_eq!(
264 AssetIdForTrustBackedAssetsConvert::<TrustBackedAssetsPalletLocation>::convert_back(
265 &local_asset_id
266 )
267 .unwrap(),
268 expected_reverse_ref
269 );
270 assert_eq!(
271 AssetIdForTrustBackedAssetsConvert::<TrustBackedAssetsPalletLocation>::convert(
272 &expected_reverse_ref
273 )
274 .unwrap(),
275 local_asset_id
276 );
277 }
278
279 #[test]
280 fn trust_backed_assets_match_fungibles_works() {
281 pezframe_support::parameter_types! {
282 pub TrustBackedAssetsPalletLocation: Location = Location::new(0, [PalletInstance(13)]);
283 }
284 type TrustBackedAssetsConvert =
286 TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, u128>;
287
288 let test_data = vec![
289 (ma_1000(0, [PalletInstance(13)].into()), Err(MatchError::AssetIdConversionFailed)),
291 (
292 ma_1000(0, [PalletInstance(13), GeneralKey { data: [0; 32], length: 32 }].into()),
293 Err(MatchError::AssetIdConversionFailed),
294 ),
295 (
296 ma_1000(0, [PalletInstance(13), Teyrchain(1000)].into()),
297 Err(MatchError::AssetIdConversionFailed),
298 ),
299 (ma_1000(0, [PalletInstance(13), GeneralIndex(1234)].into()), Ok((1234, 1000))),
301 (
302 ma_1000(0, [PalletInstance(13), GeneralIndex(1234), GeneralIndex(2222)].into()),
303 Ok((1234, 1000)),
304 ),
305 (
306 ma_1000(
307 0,
308 [
309 PalletInstance(13),
310 GeneralIndex(1234),
311 GeneralIndex(2222),
312 GeneralKey { data: [0; 32], length: 32 },
313 ]
314 .into(),
315 ),
316 Ok((1234, 1000)),
317 ),
318 (
320 ma_1000(0, [PalletInstance(77), GeneralIndex(1234)].into()),
321 Err(MatchError::AssetNotHandled),
322 ),
323 (
324 ma_1000(0, [PalletInstance(77), GeneralIndex(1234), GeneralIndex(2222)].into()),
325 Err(MatchError::AssetNotHandled),
326 ),
327 (
329 ma_1000(1, [PalletInstance(13), GeneralIndex(1234)].into()),
330 Err(MatchError::AssetNotHandled),
331 ),
332 (
333 ma_1000(1, [PalletInstance(13), GeneralIndex(1234), GeneralIndex(2222)].into()),
334 Err(MatchError::AssetNotHandled),
335 ),
336 (
337 ma_1000(1, [PalletInstance(77), GeneralIndex(1234)].into()),
338 Err(MatchError::AssetNotHandled),
339 ),
340 (
341 ma_1000(1, [PalletInstance(77), GeneralIndex(1234), GeneralIndex(2222)].into()),
342 Err(MatchError::AssetNotHandled),
343 ),
344 (
346 ma_1000(2, [PalletInstance(13), GeneralIndex(1234)].into()),
347 Err(MatchError::AssetNotHandled),
348 ),
349 (
350 ma_1000(2, [PalletInstance(13), GeneralIndex(1234), GeneralIndex(2222)].into()),
351 Err(MatchError::AssetNotHandled),
352 ),
353 (ma_1000(0, [PalletInstance(77)].into()), Err(MatchError::AssetNotHandled)),
355 (ma_1000(1, [PalletInstance(13)].into()), Err(MatchError::AssetNotHandled)),
356 (ma_1000(2, [PalletInstance(13)].into()), Err(MatchError::AssetNotHandled)),
357 ];
358
359 for (asset, expected_result) in test_data {
360 assert_eq!(
361 <TrustBackedAssetsConvert as MatchesFungibles<AssetIdForTrustBackedAssets, u128>>::matches_fungibles(&asset.clone().try_into().unwrap()),
362 expected_result, "asset: {:?}", asset);
363 }
364 }
365
366 #[test]
367 fn foreign_assets_converted_concrete_id_converter_works() {
368 pezframe_support::parameter_types! {
369 pub Teyrchain100Pattern: Location = Location::new(1, [Teyrchain(100)]);
370 pub UniversalLocationNetworkId: NetworkId = NetworkId::ByGenesis([9; 32]);
371 }
372
373 type Convert = ForeignAssetsConvertedConcreteId<
375 (
376 StartsWith<Teyrchain100Pattern>,
377 StartsWithExplicitGlobalConsensus<UniversalLocationNetworkId>,
378 ),
379 u128,
380 xcm::v4::Location,
381 WithLatestLocationConverter<xcm::v4::Location>,
382 >;
383
384 let test_data = vec![
385 (ma_1000(0, Here), Err(MatchError::AssetNotHandled)),
387 (ma_1000(0, [Teyrchain(100)].into()), Err(MatchError::AssetNotHandled)),
388 (
389 ma_1000(0, [PalletInstance(13), GeneralIndex(1234)].into()),
390 Err(MatchError::AssetNotHandled),
391 ),
392 (ma_1000(1, Here), Err(MatchError::AssetNotHandled)),
394 (ma_1000(1, [Teyrchain(100)].into()), Err(MatchError::AssetNotHandled)),
396 (
397 ma_1000(1, [Teyrchain(100), GeneralIndex(1234)].into()),
398 Err(MatchError::AssetNotHandled),
399 ),
400 (
401 ma_1000(1, [Teyrchain(100), PalletInstance(13), GeneralIndex(1234)].into()),
402 Err(MatchError::AssetNotHandled),
403 ),
404 (
406 ma_1000(1, [GlobalConsensus(NetworkId::ByGenesis([9; 32]))].into()),
407 Err(MatchError::AssetNotHandled),
408 ),
409 (
410 ma_1000(2, [GlobalConsensus(NetworkId::ByGenesis([9; 32]))].into()),
411 Err(MatchError::AssetNotHandled),
412 ),
413 (
414 ma_1000(
415 2,
416 [
417 GlobalConsensus(NetworkId::ByGenesis([9; 32])),
418 Teyrchain(200),
419 GeneralIndex(1234),
420 ]
421 .into(),
422 ),
423 Err(MatchError::AssetNotHandled),
424 ),
425 (
427 ma_1000(1, [Teyrchain(200)].into()),
428 Ok((xcm::v4::Location::new(1, [xcm::v4::Junction::Teyrchain(200)]), 1000)),
429 ),
430 (
431 ma_1000(2, [Teyrchain(200)].into()),
432 Ok((xcm::v4::Location::new(2, [xcm::v4::Junction::Teyrchain(200)]), 1000)),
433 ),
434 (
435 ma_1000(1, [Teyrchain(200), GeneralIndex(1234)].into()),
436 Ok((
437 xcm::v4::Location::new(
438 1,
439 [xcm::v4::Junction::Teyrchain(200), xcm::v4::Junction::GeneralIndex(1234)],
440 ),
441 1000,
442 )),
443 ),
444 (
445 ma_1000(2, [Teyrchain(200), GeneralIndex(1234)].into()),
446 Ok((
447 xcm::v4::Location::new(
448 2,
449 [xcm::v4::Junction::Teyrchain(200), xcm::v4::Junction::GeneralIndex(1234)],
450 ),
451 1000,
452 )),
453 ),
454 (
455 ma_1000(2, [GlobalConsensus(NetworkId::ByGenesis([7; 32]))].into()),
456 Ok((
457 xcm::v4::Location::new(
458 2,
459 [xcm::v4::Junction::GlobalConsensus(xcm::v4::NetworkId::ByGenesis(
460 [7; 32],
461 ))],
462 ),
463 1000,
464 )),
465 ),
466 (
467 ma_1000(
468 2,
469 [
470 GlobalConsensus(NetworkId::ByGenesis([7; 32])),
471 Teyrchain(200),
472 GeneralIndex(1234),
473 ]
474 .into(),
475 ),
476 Ok((
477 xcm::v4::Location::new(
478 2,
479 [
480 xcm::v4::Junction::GlobalConsensus(xcm::v4::NetworkId::ByGenesis(
481 [7; 32],
482 )),
483 xcm::v4::Junction::Teyrchain(200),
484 xcm::v4::Junction::GeneralIndex(1234),
485 ],
486 ),
487 1000,
488 )),
489 ),
490 ];
491
492 for (asset, expected_result) in test_data {
493 assert_eq!(
494 <Convert as MatchesFungibles<xcm::v4::Location, u128>>::matches_fungibles(
495 &asset.clone().try_into().unwrap()
496 ),
497 expected_result,
498 "asset: {:?}",
499 asset
500 );
501 }
502 }
503
504 fn ma_1000(parents: u8, interior: Junctions) -> Asset {
506 (Location::new(parents, interior), 1000).into()
507 }
508}