diff --git a/CHANGELOG.md b/CHANGELOG.md index 206de34099..1547495505 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -123,6 +123,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Update the fellowship salary budget amount in alignment with the Fellowship Salary [RFC](https://github.com/polkadot-fellows/RFCs/pull/50) ([polkadot-fellows/runtimes#121](https://github.com/polkadot-fellows/runtimes/pull/121)) - Set up an account ID for the local root location on Polkadot Collectives ([polkadot-fellows/runtimes#125](https://github.com/polkadot-fellows/runtimes/pull/125)) - Increase confirmation period for treasury spend tracks on Polkadot & Kusama ([polkadot-fellows/runtimes#119](https://github.com/polkadot-fellows/runtimes/pull/119)) +- Drop ED requirement for transaction payments with an exchangeable asset ([polkadot-fellows/runtimes#310](https://github.com/polkadot-fellows/runtimes/pull/310)) ### Added diff --git a/system-parachains/asset-hubs/asset-hub-kusama/src/impls.rs b/system-parachains/asset-hubs/asset-hub-kusama/src/impls.rs new file mode 100644 index 0000000000..68a3bfb318 --- /dev/null +++ b/system-parachains/asset-hubs/asset-hub-kusama/src/impls.rs @@ -0,0 +1,303 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::*; + +// TODO: move implementations to the polkadot-sdk. +pub mod tx_payment { + use super::*; + use core::marker::PhantomData; + use frame_support::{ + ensure, + pallet_prelude::{InvalidTransaction, TransactionValidityError}, + traits::{ + fungibles::{Balanced as FungiblesBalanced, Inspect as FungiblesInspect}, + tokens::{Fortitude, Precision, Preservation}, + Defensive, OnUnbalanced, SameOrOther, + }, + }; + use pallet_asset_conversion::{Pallet as AssetConversion, SwapCredit}; + use pallet_asset_conversion_tx_payment::OnChargeAssetTransaction; + use pallet_transaction_payment::OnChargeTransaction; + use sp_core::Get; + use sp_runtime::{ + traits::{DispatchInfoOf, PostDispatchInfoOf, Zero}, + Saturating, + }; + + /// Implements [`OnChargeTransaction`] for [`pallet_transaction_payment`], where the asset class + /// used to pay the fee is defined with the `A` type parameter (eg. KSM location) and accessed + /// via the type implementing the [`frame_support::traits::fungibles`] trait. + /// + /// This implementation with the `fungibles` trait is necessary to set up + /// [`pallet_asset_conversion_tx_payment`] with the [`SwapCreditAdapter`] type. For both types, + /// the credit types they handle must be the same, therefore they must be credits of + /// `fungibles`. + pub struct FungiblesAdapter(PhantomData<(F, A, OU)>); + + impl OnChargeTransaction for FungiblesAdapter + where + T: pallet_transaction_payment::Config, + F: fungibles::Balanced, + A: Get, + OU: OnUnbalanced>, + { + type LiquidityInfo = Option>; + type Balance = F::Balance; + + fn withdraw_fee( + who: &::AccountId, + _call: &::RuntimeCall, + _dispatch_info: &DispatchInfoOf<::RuntimeCall>, + fee: Self::Balance, + _tip: Self::Balance, + ) -> Result { + if fee.is_zero() { + return Ok(None) + } + + match F::withdraw( + A::get(), + who, + fee, + Precision::Exact, + Preservation::Preserve, + Fortitude::Polite, + ) { + Ok(imbalance) => Ok(Some(imbalance)), + Err(_) => Err(InvalidTransaction::Payment.into()), + } + } + + fn correct_and_deposit_fee( + who: &::AccountId, + _dispatch_info: &DispatchInfoOf<::RuntimeCall>, + _post_info: &PostDispatchInfoOf<::RuntimeCall>, + corrected_fee: Self::Balance, + _tip: Self::Balance, + already_withdrawn: Self::LiquidityInfo, + ) -> Result<(), TransactionValidityError> { + let Some(paid) = already_withdrawn else { + return Ok(()); + }; + // Make sure the credit is in desired asset id. + ensure!(paid.asset() == A::get(), InvalidTransaction::Payment); + // Calculate how much refund we should return. + let refund_amount = paid.peek().saturating_sub(corrected_fee); + // Refund to the the account that paid the fees if it was not removed by the + // dispatched function. If fails for any reason (eg. ED requirement is not met) no + // refund given. + let refund_debt = + if F::total_balance(A::get(), who).is_zero() || refund_amount.is_zero() { + fungibles::Debt::::zero(A::get()) + } else { + F::deposit(A::get(), who, refund_amount, Precision::BestEffort) + .unwrap_or_else(|_| fungibles::Debt::::zero(A::get())) + }; + // Merge the imbalance caused by paying the fees and refunding parts of it again. + let adjusted_paid: fungibles::Credit = + match paid.offset(refund_debt).defensive_proof("credits should be identical") { + Ok(SameOrOther::Same(credit)) => credit, + // Paid amount is fully refunded. + Ok(SameOrOther::None) => fungibles::Credit::::zero(A::get()), + // Should never fail as at this point the asset id is always valid and the + // refund amount is not greater than paid amount. + _ => return Err(InvalidTransaction::Payment.into()), + }; + // No separation for simplicity. + // In our case the fees and the tips are deposited to the same pot. + // We cannot call [`OnUnbalanced::on_unbalanceds`] since fungibles credit does not + // implement `Imbalanced` trait. + OU::on_unbalanced(adjusted_paid); + Ok(()) + } + } + + type LiquidityInfoOf = + <::OnChargeTransaction as OnChargeTransaction< + T, + >>::LiquidityInfo; + + /// Implements [`OnChargeAssetTransaction`] for [`pallet_asset_conversion_tx_payment`], where + /// the asset class used to pay the fee is defined with the `A` type parameter (eg. DOT + /// location) and accessed via the type implementing the [`frame_support::traits::fungibles`] + /// trait. + pub struct SwapCreditAdapter(PhantomData<(A, S)>); + impl OnChargeAssetTransaction for SwapCreditAdapter + where + A: Get, + S: SwapCredit< + T::AccountId, + Balance = T::Balance, + AssetKind = T::AssetKind, + Credit = fungibles::Credit, + >, + + T: pallet_asset_conversion_tx_payment::Config, + T::Fungibles: + fungibles::Inspect, + T::OnChargeTransaction: + OnChargeTransaction>, + { + type AssetId = T::AssetKind; + type Balance = T::Balance; + type LiquidityInfo = T::Balance; + + fn withdraw_fee( + who: &::AccountId, + _call: &::RuntimeCall, + _dispatch_info: &DispatchInfoOf<::RuntimeCall>, + asset_id: Self::AssetId, + fee: Self::Balance, + _tip: Self::Balance, + ) -> Result<(LiquidityInfoOf, Self::LiquidityInfo, T::Balance), TransactionValidityError> + { + let asset_fee = AssetConversion::::quote_price_tokens_for_exact_tokens( + asset_id.clone(), + A::get(), + fee, + true, + ) + .ok_or(InvalidTransaction::Payment)?; + + let asset_fee_credit = T::Assets::withdraw( + asset_id.clone(), + who, + asset_fee, + Precision::Exact, + Preservation::Preserve, + Fortitude::Polite, + ) + .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment))?; + + let (fee_credit, change) = match S::swap_tokens_for_exact_tokens( + vec![asset_id, A::get()], + asset_fee_credit, + fee, + ) { + Ok((fee_credit, change)) => (fee_credit, change), + Err((credit_in, _)) => { + // The swap should not error since the price quote was successful. + let _ = T::Assets::resolve(who, credit_in).defensive(); + return Err(InvalidTransaction::Payment.into()) + }, + }; + + // Should be always zero since the exact price was quoted before. + ensure!(change.peek().is_zero(), InvalidTransaction::Payment); + + Ok((Some(fee_credit), fee, asset_fee)) + } + fn correct_and_deposit_fee( + who: &::AccountId, + dispatch_info: &DispatchInfoOf<::RuntimeCall>, + post_info: &PostDispatchInfoOf<::RuntimeCall>, + corrected_fee: Self::Balance, + tip: Self::Balance, + fee_paid: LiquidityInfoOf, + _received_exchanged: Self::LiquidityInfo, + asset_id: Self::AssetId, + initial_asset_consumed: T::Balance, + ) -> Result { + let Some(fee_paid) = fee_paid else { + return Ok(Zero::zero()); + }; + // Try to refund if the fee paid is more than the corrected fee and the account was not + // removed by the dispatched function. + let (fee, fee_in_asset) = if fee_paid.peek() > corrected_fee && + !T::Assets::total_balance(asset_id.clone(), who).is_zero() + { + let refund_amount = fee_paid.peek().saturating_sub(corrected_fee); + // Check if the refund amount can be swapped back into the asset used by `who` for + // fee payment. + let refund_asset_amount = + AssetConversion::::quote_price_exact_tokens_for_tokens( + A::get(), + asset_id.clone(), + refund_amount, + true, + ) + // No refund given if it cannot be swapped back. + .unwrap_or(Zero::zero()); + + // Deposit the refund before the swap to ensure it can be processed. + let debt = match T::Assets::deposit( + asset_id.clone(), + who, + refund_asset_amount, + Precision::BestEffort, + ) { + Ok(debt) => debt, + // No refund given since it cannot be deposited. + Err(_) => fungibles::Debt::::zero(asset_id.clone()), + }; + + if debt.peek().is_zero() { + // No refund given. + (fee_paid, initial_asset_consumed) + } else { + let (refund, fee_paid) = fee_paid.split(refund_amount); + match S::swap_exact_tokens_for_tokens( + vec![A::get(), asset_id], + refund, + Some(refund_asset_amount), + ) { + Ok(refund_asset) => { + match refund_asset.offset(debt) { + Ok(SameOrOther::None) => {}, + // This arm should never be reached, as the amount of `debt` is + // expected to be exactly equal to the amount of `refund_asset` + // credit. + _ => return Err(InvalidTransaction::Payment.into()), + }; + (fee_paid, initial_asset_consumed.saturating_sub(refund_asset_amount)) + }, + // The error should not occur since swap was quoted before. + Err((refund, _)) => { + match T::Assets::settle(who, debt, Preservation::Expendable) { + Ok(dust) => + ensure!(dust.peek().is_zero(), InvalidTransaction::Payment), + // The error should not occur as the `debt` was just withdrawn + // above. + Err(_) => return Err(InvalidTransaction::Payment.into()), + }; + let fee_paid = fee_paid.merge(refund).map_err(|_| { + // The error should never occur since `fee_paid` and `refund` are + // credits of the same asset. + TransactionValidityError::from(InvalidTransaction::Payment) + })?; + (fee_paid, initial_asset_consumed) + }, + } + } + } else { + (fee_paid, initial_asset_consumed) + }; + + // Refund is already processed. + let corrected_fee = fee.peek(); + // Deposit fee. + T::OnChargeTransaction::correct_and_deposit_fee( + who, + dispatch_info, + post_info, + corrected_fee, + tip, + Some(fee), + ) + .map(|_| fee_in_asset) + } + } +} diff --git a/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs b/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs index 1e4afc6a7d..84c05c6a85 100644 --- a/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs +++ b/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs @@ -24,6 +24,7 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +mod impls; mod weights; pub mod xcm_config; @@ -69,11 +70,10 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, EnsureSigned, EnsureSignedBy, }; -use pallet_asset_conversion_tx_payment::AssetConversionAdapter; use pallet_nfts::PalletFeatures; use parachains_common::{ - impls::DealWithFees, message_queue::*, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, - BlockNumber, Hash, Header, Nonce, Signature, + message_queue::*, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, Hash, + Header, Nonce, Signature, }; use sp_runtime::RuntimeDebug; pub use system_parachains_constants::SLOT_DURATION; @@ -254,12 +254,16 @@ impl pallet_vesting::Config for Runtime { parameter_types! { /// Relay Chain `TransactionByteFee` / 10 pub const TransactionByteFee: Balance = system_parachains_constants::kusama::fee::TRANSACTION_BYTE_FEE; + pub StakingPot: AccountId = CollatorSelection::account_id(); } impl pallet_transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = - pallet_transaction_payment::CurrencyAdapter>; + type OnChargeTransaction = impls::tx_payment::FungiblesAdapter< + NativeAndAssets, + KsmLocationV3, + ResolveAssetTo, + >; type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; @@ -807,7 +811,7 @@ impl pallet_asset_conversion_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Fungibles = LocalAndForeignAssets; type OnChargeAssetTransaction = - AssetConversionAdapter; + impls::tx_payment::SwapCreditAdapter; } parameter_types! { diff --git a/system-parachains/asset-hubs/asset-hub-polkadot/src/impls.rs b/system-parachains/asset-hubs/asset-hub-polkadot/src/impls.rs index 07d682f18a..e0bc895072 100644 --- a/system-parachains/asset-hubs/asset-hub-polkadot/src/impls.rs +++ b/system-parachains/asset-hubs/asset-hub-polkadot/src/impls.rs @@ -72,3 +72,290 @@ pub(crate) mod pool { } } } + +// TODO: move implementations to the polkadot-sdk. +pub mod tx_payment { + use super::*; + use core::marker::PhantomData; + use frame_support::{ + ensure, + pallet_prelude::{InvalidTransaction, TransactionValidityError}, + traits::{ + fungibles::{Balanced as FungiblesBalanced, Inspect as FungiblesInspect}, + tokens::{Fortitude, Precision, Preservation}, + Defensive, OnUnbalanced, SameOrOther, + }, + }; + use pallet_asset_conversion::{Pallet as AssetConversion, SwapCredit}; + use pallet_asset_conversion_tx_payment::OnChargeAssetTransaction; + use pallet_transaction_payment::OnChargeTransaction; + use sp_core::Get; + use sp_runtime::{ + traits::{DispatchInfoOf, PostDispatchInfoOf, Zero}, + Saturating, + }; + + /// Implements [`OnChargeTransaction`] for [`pallet_transaction_payment`], where the asset class + /// used to pay the fee is defined with the `A` type parameter (eg. KSM location) and accessed + /// via the type implementing the [`frame_support::traits::fungibles`] trait. + /// + /// This implementation with the `fungibles` trait is necessary to set up + /// [`pallet_asset_conversion_tx_payment`] with the [`SwapCreditAdapter`] type. For both types, + /// the credit types they handle must be the same, therefore they must be credits of + /// `fungibles`. + pub struct FungiblesAdapter(PhantomData<(F, A, OU)>); + + impl OnChargeTransaction for FungiblesAdapter + where + T: pallet_transaction_payment::Config, + F: fungibles::Balanced, + A: Get, + OU: OnUnbalanced>, + { + type LiquidityInfo = Option>; + type Balance = F::Balance; + + fn withdraw_fee( + who: &::AccountId, + _call: &::RuntimeCall, + _dispatch_info: &DispatchInfoOf<::RuntimeCall>, + fee: Self::Balance, + _tip: Self::Balance, + ) -> Result { + if fee.is_zero() { + return Ok(None) + } + + match F::withdraw( + A::get(), + who, + fee, + Precision::Exact, + Preservation::Preserve, + Fortitude::Polite, + ) { + Ok(imbalance) => Ok(Some(imbalance)), + Err(_) => Err(InvalidTransaction::Payment.into()), + } + } + + fn correct_and_deposit_fee( + who: &::AccountId, + _dispatch_info: &DispatchInfoOf<::RuntimeCall>, + _post_info: &PostDispatchInfoOf<::RuntimeCall>, + corrected_fee: Self::Balance, + _tip: Self::Balance, + already_withdrawn: Self::LiquidityInfo, + ) -> Result<(), TransactionValidityError> { + let Some(paid) = already_withdrawn else { + return Ok(()); + }; + // Make sure the credit is in desired asset id. + ensure!(paid.asset() == A::get(), InvalidTransaction::Payment); + // Calculate how much refund we should return. + let refund_amount = paid.peek().saturating_sub(corrected_fee); + // Refund to the the account that paid the fees if it was not removed by the + // dispatched function. If fails for any reason (eg. ED requirement is not met) no + // refund given. + let refund_debt = + if F::total_balance(A::get(), who).is_zero() || refund_amount.is_zero() { + fungibles::Debt::::zero(A::get()) + } else { + F::deposit(A::get(), who, refund_amount, Precision::BestEffort) + .unwrap_or_else(|_| fungibles::Debt::::zero(A::get())) + }; + // Merge the imbalance caused by paying the fees and refunding parts of it again. + let adjusted_paid: fungibles::Credit = + match paid.offset(refund_debt).defensive_proof("credits should be identical") { + Ok(SameOrOther::Same(credit)) => credit, + // Paid amount is fully refunded. + Ok(SameOrOther::None) => fungibles::Credit::::zero(A::get()), + // Should never fail as at this point the asset id is always valid and the + // refund amount is not greater than paid amount. + _ => return Err(InvalidTransaction::Payment.into()), + }; + // No separation for simplicity. + // In our case the fees and the tips are deposited to the same pot. + // We cannot call [`OnUnbalanced::on_unbalanceds`] since fungibles credit does not + // implement `Imbalanced` trait. + OU::on_unbalanced(adjusted_paid); + Ok(()) + } + } + + type LiquidityInfoOf = + <::OnChargeTransaction as OnChargeTransaction< + T, + >>::LiquidityInfo; + + /// Implements [`OnChargeAssetTransaction`] for [`pallet_asset_conversion_tx_payment`], where + /// the asset class used to pay the fee is defined with the `A` type parameter (eg. DOT + /// location) and accessed via the type implementing the [`frame_support::traits::fungibles`] + /// trait. + pub struct SwapCreditAdapter(PhantomData<(A, S)>); + impl OnChargeAssetTransaction for SwapCreditAdapter + where + A: Get, + S: SwapCredit< + T::AccountId, + Balance = T::Balance, + AssetKind = T::AssetKind, + Credit = fungibles::Credit, + >, + + T: pallet_asset_conversion_tx_payment::Config, + T::Fungibles: + fungibles::Inspect, + T::OnChargeTransaction: + OnChargeTransaction>, + { + type AssetId = T::AssetKind; + type Balance = T::Balance; + type LiquidityInfo = T::Balance; + + fn withdraw_fee( + who: &::AccountId, + _call: &::RuntimeCall, + _dispatch_info: &DispatchInfoOf<::RuntimeCall>, + asset_id: Self::AssetId, + fee: Self::Balance, + _tip: Self::Balance, + ) -> Result<(LiquidityInfoOf, Self::LiquidityInfo, T::Balance), TransactionValidityError> + { + let asset_fee = AssetConversion::::quote_price_tokens_for_exact_tokens( + asset_id.clone(), + A::get(), + fee, + true, + ) + .ok_or(InvalidTransaction::Payment)?; + + let asset_fee_credit = T::Assets::withdraw( + asset_id.clone(), + who, + asset_fee, + Precision::Exact, + Preservation::Preserve, + Fortitude::Polite, + ) + .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment))?; + + let (fee_credit, change) = match S::swap_tokens_for_exact_tokens( + vec![asset_id, A::get()], + asset_fee_credit, + fee, + ) { + Ok((fee_credit, change)) => (fee_credit, change), + Err((credit_in, _)) => { + // The swap should not error since the price quote was successful. + let _ = T::Assets::resolve(who, credit_in).defensive(); + return Err(InvalidTransaction::Payment.into()) + }, + }; + + // Should be always zero since the exact price was quoted before. + ensure!(change.peek().is_zero(), InvalidTransaction::Payment); + + Ok((Some(fee_credit), fee, asset_fee)) + } + fn correct_and_deposit_fee( + who: &::AccountId, + dispatch_info: &DispatchInfoOf<::RuntimeCall>, + post_info: &PostDispatchInfoOf<::RuntimeCall>, + corrected_fee: Self::Balance, + tip: Self::Balance, + fee_paid: LiquidityInfoOf, + _received_exchanged: Self::LiquidityInfo, + asset_id: Self::AssetId, + initial_asset_consumed: T::Balance, + ) -> Result { + let Some(fee_paid) = fee_paid else { + return Ok(Zero::zero()); + }; + // Try to refund if the fee paid is more than the corrected fee and the account was not + // removed by the dispatched function. + let (fee, fee_in_asset) = if fee_paid.peek() > corrected_fee && + !T::Assets::total_balance(asset_id.clone(), who).is_zero() + { + let refund_amount = fee_paid.peek().saturating_sub(corrected_fee); + // Check if the refund amount can be swapped back into the asset used by `who` for + // fee payment. + let refund_asset_amount = + AssetConversion::::quote_price_exact_tokens_for_tokens( + A::get(), + asset_id.clone(), + refund_amount, + true, + ) + // No refund given if it cannot be swapped back. + .unwrap_or(Zero::zero()); + + // Deposit the refund before the swap to ensure it can be processed. + let debt = match T::Assets::deposit( + asset_id.clone(), + who, + refund_asset_amount, + Precision::BestEffort, + ) { + Ok(debt) => debt, + // No refund given since it cannot be deposited. + Err(_) => fungibles::Debt::::zero(asset_id.clone()), + }; + + if debt.peek().is_zero() { + // No refund given. + (fee_paid, initial_asset_consumed) + } else { + let (refund, fee_paid) = fee_paid.split(refund_amount); + match S::swap_exact_tokens_for_tokens( + vec![A::get(), asset_id], + refund, + Some(refund_asset_amount), + ) { + Ok(refund_asset) => { + match refund_asset.offset(debt) { + Ok(SameOrOther::None) => {}, + // This arm should never be reached, as the amount of `debt` is + // expected to be exactly equal to the amount of `refund_asset` + // credit. + _ => return Err(InvalidTransaction::Payment.into()), + }; + (fee_paid, initial_asset_consumed.saturating_sub(refund_asset_amount)) + }, + // The error should not occur since swap was quoted before. + Err((refund, _)) => { + match T::Assets::settle(who, debt, Preservation::Expendable) { + Ok(dust) => + ensure!(dust.peek().is_zero(), InvalidTransaction::Payment), + // The error should not occur as the `debt` was just withdrawn + // above. + Err(_) => return Err(InvalidTransaction::Payment.into()), + }; + let fee_paid = fee_paid.merge(refund).map_err(|_| { + // The error should never occur since `fee_paid` and `refund` are + // credits of the same asset. + TransactionValidityError::from(InvalidTransaction::Payment) + })?; + (fee_paid, initial_asset_consumed) + }, + } + } + } else { + (fee_paid, initial_asset_consumed) + }; + + // Refund is already processed. + let corrected_fee = fee.peek(); + // Deposit fee. + T::OnChargeTransaction::correct_and_deposit_fee( + who, + dispatch_info, + post_info, + corrected_fee, + tip, + Some(fee), + ) + .map(|_| fee_in_asset) + } + } +} diff --git a/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs b/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs index d0bdc2edb1..1c97b9c0ed 100644 --- a/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs +++ b/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs @@ -106,8 +106,8 @@ use frame_system::{ }; use pallet_nfts::PalletFeatures; use parachains_common::{ - impls::DealWithFees, message_queue::*, AccountId, AssetHubPolkadotAuraId as AuraId, - AssetIdForTrustBackedAssets, Balance, BlockNumber, Hash, Header, Nonce, Signature, + message_queue::*, AccountId, AssetHubPolkadotAuraId as AuraId, AssetIdForTrustBackedAssets, + Balance, BlockNumber, Hash, Header, Nonce, Signature, }; use sp_runtime::RuntimeDebug; @@ -272,12 +272,16 @@ impl pallet_vesting::Config for Runtime { parameter_types! { /// Relay Chain `TransactionByteFee` / 10 pub const TransactionByteFee: Balance = system_parachains_constants::polkadot::fee::TRANSACTION_BYTE_FEE; + pub StakingPot: AccountId = CollatorSelection::account_id(); } impl pallet_transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = - pallet_transaction_payment::CurrencyAdapter>; + type OnChargeTransaction = impls::tx_payment::FungiblesAdapter< + NativeAndAssets, + DotLocationV3, + ResolveAssetTo, + >; type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; @@ -732,11 +736,8 @@ impl pallet_collator_selection::Config for Runtime { impl pallet_asset_conversion_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Fungibles = LocalAndForeignAssets; - type OnChargeAssetTransaction = pallet_asset_conversion_tx_payment::AssetConversionAdapter< - Balances, - AssetConversion, - DotLocationV3, - >; + type OnChargeAssetTransaction = + impls::tx_payment::SwapCreditAdapter; } parameter_types! {