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

            
17
use core::marker::PhantomData;
18

            
19
use frame_support::traits::{
20
	fungible::{self, NativeOrWithId},
21
	tokens::ConversionFromAssetBalance,
22
};
23
use moonbeam_core_primitives::{AssetId, Balance};
24
use pallet_xcm_weight_trader::RELATIVE_PRICE_DECIMALS;
25
use sp_runtime::traits::MaybeEquivalence;
26

            
27
pub struct AssetRateConverter<T, NativeAsset>(PhantomData<(T, NativeAsset)>);
28
impl<
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
54
	fn from_asset_balance(
39
54
		balance: Balance,
40
54
		asset_kind: NativeOrWithId<AssetId>,
41
54
	) -> Result<Balance, Self::Error> {
42
54
		match asset_kind {
43
27
			NativeOrWithId::Native => Ok(balance),
44
27
			NativeOrWithId::WithId(asset_id) => {
45
27
				let location = pallet_moonbeam_foreign_assets::Pallet::<T>::convert_back(&asset_id)
46
27
					.ok_or(pallet_xcm_weight_trader::Error::<T>::AssetNotFound)?;
47
27
				let relative_price =
48
27
					pallet_xcm_weight_trader::Pallet::<T>::get_asset_relative_price(&location)
49
27
						.ok_or(pallet_xcm_weight_trader::Error::<T>::AssetNotFound)?;
50
27
				Ok(balance
51
27
					.checked_mul(relative_price)
52
27
					.ok_or(pallet_xcm_weight_trader::Error::<T>::PriceOverflow)?
53
27
					.checked_div(10u128.pow(RELATIVE_PRICE_DECIMALS))
54
27
					.ok_or(pallet_xcm_weight_trader::Error::<T>::PriceOverflow)?)
55
			}
56
		}
57
54
	}
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
}