moonbeam_runtime_common/
impl_multiasset_paymaster.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 frame_support::traits::fungible;
18use frame_support::traits::{
19	fungible::NativeOrWithId,
20	tokens::{Pay, Preservation::Expendable},
21};
22use moonbeam_core_primitives::{AssetId, Balance};
23use sp_core::{Get, U256};
24use sp_runtime::DispatchError;
25
26pub struct MultiAssetPaymaster<R, TreasuryAccount, NativeAsset>(
27	sp_std::marker::PhantomData<(R, TreasuryAccount, NativeAsset)>,
28);
29impl<R, TreasuryAccount, NativeAsset> Pay for MultiAssetPaymaster<R, TreasuryAccount, NativeAsset>
30where
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	fn pay(
41		who: &Self::Beneficiary,
42		asset_kind: Self::AssetKind,
43		amount: Self::Balance,
44	) -> Result<Self::Id, Self::Error> {
45		match asset_kind {
46			Self::AssetKind::Native => {
47				<NativeAsset as fungible::Mutate<_>>::transfer(
48					&TreasuryAccount::get(),
49					who,
50					amount
51						.try_into()
52						.map_err(|_| DispatchError::Other("failed to convert amount"))?,
53					Expendable,
54				)?;
55				Ok(())
56			}
57			Self::AssetKind::WithId(id) => pallet_moonbeam_foreign_assets::Pallet::<R>::transfer(
58				id,
59				TreasuryAccount::get(),
60				who.clone(),
61				U256::from(amount as u128),
62			)
63			.map_err(|_| Self::Error::Other("failed to transfer amount")),
64		}
65	}
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}