moonbeam_runtime_common/
impl_asset_conversion.rs

1// Copyright 2025 Moonbeam foundation
2// This file is part of Moonbeam.
3
4// Moonbeam is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Moonbeam is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16
17use core::marker::PhantomData;
18
19use frame_support::traits::{
20	fungible::{self, NativeOrWithId},
21	tokens::ConversionFromAssetBalance,
22};
23use moonbeam_core_primitives::{AssetId, Balance};
24use pallet_xcm_weight_trader::RELATIVE_PRICE_DECIMALS;
25use sp_runtime::traits::MaybeEquivalence;
26
27pub struct AssetRateConverter<T, NativeAsset>(PhantomData<(T, NativeAsset)>);
28impl<
29		T: frame_system::Config
30			+ pallet_xcm_weight_trader::Config
31			+ pallet_moonbeam_foreign_assets::Config,
32		NativeAsset: fungible::Mutate<T::AccountId> + fungible::Inspect<T::AccountId>,
33	> ConversionFromAssetBalance<Balance, NativeOrWithId<AssetId>, Balance>
34	for AssetRateConverter<T, NativeAsset>
35{
36	type Error = pallet_xcm_weight_trader::Error<T>;
37
38	fn from_asset_balance(
39		balance: Balance,
40		asset_kind: NativeOrWithId<AssetId>,
41	) -> Result<Balance, Self::Error> {
42		match asset_kind {
43			NativeOrWithId::Native => Ok(balance),
44			NativeOrWithId::WithId(asset_id) => {
45				let location = pallet_moonbeam_foreign_assets::Pallet::<T>::convert_back(&asset_id)
46					.ok_or(pallet_xcm_weight_trader::Error::<T>::AssetNotFound)?;
47				let relative_price =
48					pallet_xcm_weight_trader::Pallet::<T>::get_asset_relative_price(&location)
49						.ok_or(pallet_xcm_weight_trader::Error::<T>::AssetNotFound)?;
50				Ok(balance
51					.checked_mul(relative_price)
52					.ok_or(pallet_xcm_weight_trader::Error::<T>::PriceOverflow)?
53					.checked_div(10u128.pow(RELATIVE_PRICE_DECIMALS))
54					.ok_or(pallet_xcm_weight_trader::Error::<T>::PriceOverflow)?)
55			}
56		}
57	}
58
59	/// Set a conversion rate to `1` for the `asset_id`.
60	#[cfg(feature = "runtime-benchmarks")]
61	fn ensure_successful(asset_id: NativeOrWithId<AssetId>) {
62		use frame_support::traits::OriginTrait;
63		use xcm::latest::{Junction::Parachain, Location};
64		match asset_id {
65			NativeOrWithId::Native => (),
66			NativeOrWithId::WithId(asset_id) => {
67				if let None = pallet_moonbeam_foreign_assets::Pallet::<T>::convert_back(&asset_id) {
68					let location = Location::new(1, [Parachain(1000)]);
69					let root = <T as frame_system::Config>::RuntimeOrigin::root();
70
71					use sp_std::vec;
72					pallet_moonbeam_foreign_assets::Pallet::<T>::do_create_asset(
73						asset_id,
74						location.clone(),
75						12,
76						vec![b'M', b'T'].try_into().expect("invalid ticker"),
77						vec![b'M', b'y', b'T', b'o', b'k']
78							.try_into()
79							.expect("invalid name"),
80						None,
81					)
82					.expect("Failed to create foreign asset");
83
84					pallet_xcm_weight_trader::Pallet::<T>::add_asset(root, location.clone(), 1u128)
85						.expect("Could not add asset");
86				}
87			}
88		}
89	}
90}