use cfg_primitives::types::{AccountId, Balance};
use cfg_types::tokens::{CrossChainTransferability, CurrencyId, CustomMetadata};
use frame_support::traits::{fungibles::Mutate, Everything, Get};
use frame_system::pallet_prelude::BlockNumberFor;
use orml_traits::asset_registry::Inspect;
use polkadot_parachain_primitives::primitives::Sibling;
use sp_runtime::traits::{AccountIdConversion, Convert, MaybeEquivalence, Zero};
use sp_std::marker::PhantomData;
use staging_xcm::v4::{
Asset, AssetId,
Fungibility::Fungible,
Junction::{AccountId32, GeneralKey, Parachain},
Location, NetworkId,
};
use staging_xcm_builder::{
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
AllowTopLevelPaidExecutionFrom, DescribeAllTerminal, DescribeFamily, HashedDescription,
ParentIsPreset, SiblingParachainConvertsVia, SignedToAccountId32, TakeRevenue,
TakeWeightCredit,
};
use crate::xcm_fees::{default_per_second, native_per_second};
pub struct FixedConversionRateProvider<OrmlAssetRegistry>(PhantomData<OrmlAssetRegistry>);
impl<
OrmlAssetRegistry: orml_traits::asset_registry::Inspect<
AssetId = CurrencyId,
Balance = Balance,
CustomMetadata = CustomMetadata,
>,
> orml_traits::FixedConversionRateProvider for FixedConversionRateProvider<OrmlAssetRegistry>
{
fn get_fee_per_second(location: &Location) -> Option<u128> {
let metadata = OrmlAssetRegistry::metadata_by_location(location)?;
match metadata.additional.transferability {
CrossChainTransferability::Xcm(xcm_metadata) => xcm_metadata
.fee_per_second
.or_else(|| Some(default_per_second(metadata.decimals))),
_ => None,
}
}
}
pub fn general_key(data: &[u8]) -> staging_xcm::latest::Junction {
GeneralKey {
length: data.len().min(32) as u8,
data: cfg_utils::vec_to_fixed_array(data),
}
}
frame_support::parameter_types! {
pub CanonicalNativePerSecond: (AssetId, u128, u128) = (
Location::new(
0,
general_key(cfg_primitives::NATIVE_KEY),
).into(),
native_per_second(),
0,
);
}
pub struct AccountIdToLocation;
impl<AccountId: Into<[u8; 32]>> Convert<AccountId, Location> for AccountIdToLocation {
fn convert(account: AccountId) -> Location {
AccountId32 {
network: None,
id: account.into(),
}
.into()
}
}
pub type LocalOriginToLocation<R> = SignedToAccountId32<
<R as frame_system::Config>::RuntimeOrigin,
AccountId,
NetworkIdByGenesis<R>,
>;
pub struct NetworkIdByGenesis<T>(sp_std::marker::PhantomData<T>);
impl<T: frame_system::Config> Get<Option<NetworkId>> for NetworkIdByGenesis<T>
where
<T as frame_system::Config>::Hash: Into<[u8; 32]>,
{
fn get() -> Option<NetworkId> {
Some(NetworkId::ByGenesis(
frame_system::BlockHash::<T>::get(BlockNumberFor::<T>::zero()).into(),
))
}
}
pub struct CurrencyIdConvert<T>(PhantomData<T>);
impl<T> MaybeEquivalence<Location, CurrencyId> for CurrencyIdConvert<T>
where
T: orml_asset_registry::module::Config<AssetId = CurrencyId, CustomMetadata = CustomMetadata>
+ staging_parachain_info::Config,
{
fn convert(location: &Location) -> Option<CurrencyId> {
let para_id = staging_parachain_info::Pallet::<T>::parachain_id();
let unanchored_location = match location {
Location {
parents: 0,
interior,
} => Location {
parents: 1,
interior: interior
.clone()
.pushed_front_with(Parachain(u32::from(para_id)))
.ok()?,
},
x => x.clone(),
};
orml_asset_registry::module::Pallet::<T>::asset_id(&unanchored_location)
}
fn convert_back(id: &CurrencyId) -> Option<Location> {
orml_asset_registry::module::Pallet::<T>::metadata(id)
.filter(|m| m.additional.transferability.includes_xcm())
.and_then(|m| m.location)
.and_then(|l| l.try_into().ok())
}
}
impl<T> Convert<CurrencyId, Option<Location>> for CurrencyIdConvert<T>
where
T: orml_asset_registry::module::Config<AssetId = CurrencyId, CustomMetadata = CustomMetadata>
+ staging_parachain_info::Config,
{
fn convert(id: CurrencyId) -> Option<Location> {
<Self as MaybeEquivalence<_, _>>::convert_back(&id)
}
}
impl<T> Convert<Location, Option<CurrencyId>> for CurrencyIdConvert<T>
where
T: orml_asset_registry::module::Config<AssetId = CurrencyId, CustomMetadata = CustomMetadata>
+ staging_parachain_info::Config,
{
fn convert(location: Location) -> Option<CurrencyId> {
<Self as MaybeEquivalence<_, _>>::convert(&location)
}
}
pub struct ToTreasury<T>(PhantomData<T>);
impl<T> TakeRevenue for ToTreasury<T>
where
T: orml_asset_registry::module::Config<AssetId = CurrencyId, CustomMetadata = CustomMetadata>
+ staging_parachain_info::Config
+ pallet_restricted_tokens::Config<CurrencyId = CurrencyId, Balance = Balance>,
{
fn take_revenue(revenue: Asset) {
if let Asset {
id: AssetId(location),
fun: Fungible(amount),
} = revenue
{
if let Some(currency_id) =
<CurrencyIdConvert<T> as MaybeEquivalence<_, _>>::convert(&location)
{
let treasury_account = cfg_types::ids::TREASURY_PALLET_ID.into_account_truncating();
let _ = pallet_restricted_tokens::Pallet::<T>::mint_into(
currency_id,
&treasury_account,
amount,
);
}
}
}
}
pub type Barrier<PolkadotXcm> = (
TakeWeightCredit,
AllowTopLevelPaidExecutionFrom<Everything>,
AllowKnownQueryResponses<PolkadotXcm>,
AllowSubscriptionsFrom<Everything>,
);
pub type LocationToAccountId<RelayNetwork> = (
ParentIsPreset<AccountId>,
SiblingParachainConvertsVia<Sibling, AccountId>,
AccountId32Aliases<RelayNetwork, AccountId>,
HashedDescription<AccountId, DescribeFamily<DescribeAllTerminal>>,
);