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 frame_support::traits::fungible;
18
use frame_support::traits::{
19
	fungible::NativeOrWithId,
20
	tokens::{Pay, Preservation::Expendable},
21
};
22
use moonbeam_core_primitives::{AssetId, Balance};
23
use sp_core::{Get, U256};
24
use sp_runtime::DispatchError;
25

            
26
pub struct MultiAssetPaymaster<R, TreasuryAccount, NativeAsset>(
27
	sp_std::marker::PhantomData<(R, TreasuryAccount, NativeAsset)>,
28
);
29
impl<R, TreasuryAccount, NativeAsset> Pay for MultiAssetPaymaster<R, TreasuryAccount, NativeAsset>
30
where
31
	R: frame_system::Config + pallet_moonbeam_foreign_assets::Config,
32
	TreasuryAccount: Get<R::AccountId>,
33
	NativeAsset: fungible::Mutate<R::AccountId> + fungible::Inspect<R::AccountId>,
34
{
35
	type Balance = Balance;
36
	type Beneficiary = R::AccountId;
37
	type AssetKind = NativeOrWithId<AssetId>;
38
	type Id = ();
39
	type Error = DispatchError;
40
8
	fn pay(
41
8
		who: &Self::Beneficiary,
42
8
		asset_kind: Self::AssetKind,
43
8
		amount: Self::Balance,
44
8
	) -> Result<Self::Id, Self::Error> {
45
8
		match asset_kind {
46
4
			Self::AssetKind::Native => {
47
4
				<NativeAsset as fungible::Mutate<_>>::transfer(
48
4
					&TreasuryAccount::get(),
49
4
					who,
50
4
					amount
51
4
						.try_into()
52
4
						.map_err(|_| DispatchError::Other("failed to convert amount"))?,
53
4
					Expendable,
54
				)?;
55
4
				Ok(())
56
			}
57
4
			Self::AssetKind::WithId(id) => pallet_moonbeam_foreign_assets::Pallet::<R>::transfer(
58
4
				id,
59
4
				TreasuryAccount::get(),
60
4
				who.clone(),
61
4
				U256::from(amount as u128),
62
4
			)
63
4
			.map_err(|_| Self::Error::Other("failed to transfer amount")),
64
		}
65
8
	}
66

            
67
	fn check_payment(_id: Self::Id) -> frame_support::traits::tokens::PaymentStatus {
68
		frame_support::traits::tokens::PaymentStatus::Success
69
	}
70

            
71
	#[cfg(feature = "runtime-benchmarks")]
72
	fn ensure_successful(
73
		_beneficiary: &Self::Beneficiary,
74
		asset: Self::AssetKind,
75
		amount: Self::Balance,
76
	) {
77
		let treasury = TreasuryAccount::get();
78
		match asset {
79
			Self::AssetKind::Native => {
80
				let _ = <NativeAsset as fungible::Mutate<_>>::mint_into(
81
					&treasury,
82
					(amount as u32).into(),
83
				);
84
			}
85
			Self::AssetKind::WithId(id) => {
86
				// Fund treasury account
87
				pallet_moonbeam_foreign_assets::Pallet::<R>::mint_into(
88
					id,
89
					treasury,
90
					U256::from(amount as u128),
91
				)
92
				.expect("failed to mint asset into treasury account");
93
			}
94
		}
95
	}
96
	#[cfg(feature = "runtime-benchmarks")]
97
	fn ensure_concluded(_: Self::Id) {}
98
}