// KILT Blockchain – https://botlabs.org // Copyright (C) 2019-2024 BOTLabs GmbH // The KILT Blockchain is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // The KILT Blockchain is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . // If you feel like getting in touch with us, you can do so at info@botlabs.org use frame_support::ensure; use sp_std::marker::PhantomData; use xcm::v4::{Asset, AssetId, Fungibility, Location}; use xcm_executor::traits::{Error as XcmExecutorError, MatchesFungibles}; use crate::{Config, SwitchPair}; #[cfg(test)] mod mock; #[cfg(test)] mod tests; const LOG_TARGET: &str = "xcm::pallet-asset-switch::MatchesSwitchPairXcmFeeFungibleAsset"; /// Type implementing [MatchesFungibles] and returns the provided /// fungible amount if the specified `Location` matches the asset used by /// the switch pallet to pay for XCM fees at the configured remote location /// (`switch_pair_info.remote_xcm_fee`). pub struct MatchesSwitchPairXcmFeeFungibleAsset(PhantomData<(T, I)>); impl MatchesFungibles for MatchesSwitchPairXcmFeeFungibleAsset where T: Config, I: 'static, FungiblesBalance: From, { fn matches_fungibles(a: &Asset) -> Result<(Location, FungiblesBalance), XcmExecutorError> { log::info!(target: LOG_TARGET, "matches_fungibles {:?}", a); // 1. Retrieve switch pair from storage. let switch_pair = SwitchPair::::get().ok_or(XcmExecutorError::AssetNotHandled)?; // 2. Match stored asset ID with input asset ID. let Asset { id, fun } = switch_pair.remote_xcm_fee.clone().try_into().map_err(|e| { log::error!( target: LOG_TARGET, "Failed to convert stored remote fee asset {:?} into v4 Location with error {:?}.", switch_pair.remote_xcm_fee, e ); XcmExecutorError::AssetNotHandled })?; ensure!(id == a.id, XcmExecutorError::AssetNotHandled); // 3. Verify the stored asset is a fungible one. let Fungibility::Fungible(_) = fun else { log::info!(target: LOG_TARGET, "Stored remote fee asset {:?} is not a fungible one.", switch_pair.remote_xcm_fee); return Err(XcmExecutorError::AssetNotHandled); }; // After this ensure, we know we need to be transacting with this asset, so any // errors thrown from here onwards is a `FailedToTransactAsset` error. let AssetId(location) = id; // 4. Force input asset as a fungible one and return its amount. let Fungibility::Fungible(amount) = a.fun else { log::info!(target: LOG_TARGET, "Input asset {:?} is supposed to be fungible but it is not.", a); return Err(XcmExecutorError::AmountToBalanceConversionFailed); }; log::trace!(target: LOG_TARGET, "matched {:?}", (location.clone(), amount)); Ok((location, amount.into())) } }