use frame_support::traits::{ContainsPair, Get, OriginTrait};
use sp_runtime::traits::TryConvert;
use sp_std::{convert::TryInto, marker::PhantomData};
use xcm::latest::{Asset, AssetId, Fungibility, Junction, Location, NetworkId};
pub trait Reserve {
fn reserve(asset: &Asset) -> Option<Location>;
}
pub struct AccountIdToLocation<AccountId>(sp_std::marker::PhantomData<AccountId>);
impl<AccountId> sp_runtime::traits::Convert<AccountId, Location> for AccountIdToLocation<AccountId>
where
AccountId: Into<[u8; 20]>,
{
fn convert(account: AccountId) -> Location {
Location {
parents: 0,
interior: [Junction::AccountKey20 {
network: None,
key: account.into(),
}]
.into(),
}
}
}
pub struct SignedToAccountId20<Origin, AccountId, Network>(
sp_std::marker::PhantomData<(Origin, AccountId, Network)>,
);
impl<Origin: OriginTrait + Clone, AccountId: Into<[u8; 20]>, Network: Get<NetworkId>>
TryConvert<Origin, Location> for SignedToAccountId20<Origin, AccountId, Network>
where
Origin::PalletsOrigin: From<frame_system::RawOrigin<AccountId>>
+ TryInto<frame_system::RawOrigin<AccountId>, Error = Origin::PalletsOrigin>,
{
fn try_convert(o: Origin) -> Result<Location, Origin> {
o.try_with_caller(|caller| match caller.try_into() {
Ok(frame_system::RawOrigin::Signed(who)) => Ok(Junction::AccountKey20 {
key: who.into(),
network: Some(Network::get()),
}
.into()),
Ok(other) => Err(other.into()),
Err(other) => Err(other),
})
}
}
pub struct MultiNativeAsset<ReserveProvider>(PhantomData<ReserveProvider>);
impl<ReserveProvider> ContainsPair<Asset, Location> for MultiNativeAsset<ReserveProvider>
where
ReserveProvider: Reserve,
{
fn contains(asset: &Asset, origin: &Location) -> bool {
if let Some(ref reserve) = ReserveProvider::reserve(asset) {
if reserve == origin {
return true;
}
}
false
}
}
pub struct RelativeReserveProvider;
impl Reserve for RelativeReserveProvider {
fn reserve(asset: &Asset) -> Option<Location> {
let AssetId(location) = &asset.id;
if location.parents == 0
&& !matches!(location.first_interior(), Some(Junction::Parachain(_)))
{
Some(Location::here())
} else {
Some(location.chain_location())
}
}
}
pub struct AbsoluteAndRelativeReserve<AbsoluteMultiLocation>(PhantomData<AbsoluteMultiLocation>);
impl<AbsoluteMultiLocation> Reserve for AbsoluteAndRelativeReserve<AbsoluteMultiLocation>
where
AbsoluteMultiLocation: Get<Location>,
{
fn reserve(asset: &Asset) -> Option<Location> {
RelativeReserveProvider::reserve(asset).map(|relative_reserve| {
if relative_reserve == AbsoluteMultiLocation::get() {
Location::here()
} else {
relative_reserve
}
})
}
}
pub struct IsBridgedConcreteAssetFrom<Origin>(PhantomData<Origin>);
impl<Origin> ContainsPair<Asset, Location> for IsBridgedConcreteAssetFrom<Origin>
where
Origin: Get<Location>,
{
fn contains(asset: &Asset, origin: &Location) -> bool {
let loc = Origin::get();
&loc == origin
&& matches!(
asset,
Asset {
id: AssetId(Location { parents: 2, .. }),
fun: Fungibility::Fungible(_)
},
)
}
}