diff --git a/Cargo.lock b/Cargo.lock index 29e147b127..928f6923c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5685,8 +5685,6 @@ dependencies = [ "sp-runtime", "sp-std", "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -6376,8 +6374,6 @@ dependencies = [ "sp-runtime", "sp-std", "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -10635,6 +10631,7 @@ dependencies = [ "frame-support", "frame-system", "hex-literal", + "log", "module-asset-registry", "module-cdp-engine", "module-cdp-treasury", diff --git a/modules/asset-registry/Cargo.toml b/modules/asset-registry/Cargo.toml index f1c26a2128..5b70af58f1 100644 --- a/modules/asset-registry/Cargo.toml +++ b/modules/asset-registry/Cargo.toml @@ -16,8 +16,6 @@ frame-system = { git = "https://github.com/paritytech/substrate", branch = "polk primitives = { package = "acala-primitives", path = "../../primitives", default-features = false } xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.22", default-features = false } -xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.22", default-features = false } -xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.22", default-features = false } module-support = { path = "../support", default-features = false } @@ -46,8 +44,6 @@ std = [ "frame-system/std", "primitives/std", "xcm/std", - "xcm-builder/std", - "xcm-executor/std", "module-support/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/modules/asset-registry/src/lib.rs b/modules/asset-registry/src/lib.rs index 691d3e4eb0..0b30f9fc5f 100644 --- a/modules/asset-registry/src/lib.rs +++ b/modules/asset-registry/src/lib.rs @@ -30,10 +30,9 @@ use frame_support::{ pallet_prelude::*, traits::{Currency, EnsureOrigin}, transactional, - weights::constants::WEIGHT_PER_SECOND, }; use frame_system::pallet_prelude::*; -use module_support::{AssetIdMapping, BuyWeightRate, EVMBridge, Erc20InfoMapping, InvokeContext, Rate}; +use module_support::{AssetIdMapping, BuyWeightRate, EVMBridge, Erc20InfoMapping, InvokeContext, Ratio}; use primitives::{ currency::{ AssetIds, AssetMetadata, CurrencyIdType, DexShare, DexShareType, Erc20Id, ForeignAssetId, Lease, @@ -50,15 +49,10 @@ use scale_info::prelude::format; use sp_runtime::{traits::One, ArithmeticError, FixedPointNumber, FixedU128}; use sp_std::{boxed::Box, vec::Vec}; -// NOTE:v1::MultiLocation is used in storages, we would need to do migration if upgrade the -// MultiLocation in the future. -use xcm::opaque::latest::{prelude::XcmError, AssetId, Fungibility::Fungible, MultiAsset}; use xcm::{ v1::{Junction, Junctions::*, MultiLocation}, VersionedMultiLocation, }; -use xcm_builder::TakeRevenue; -use xcm_executor::{traits::WeightTrader, Assets}; mod mock; mod tests; @@ -565,7 +559,7 @@ impl BuyWeightRate for BuyWeightRateOfForeignAsset where BalanceOf: Into, { - fn calculate_rate(location: MultiLocation) -> Option { + fn calculate_rate(location: MultiLocation) -> Option { if let Some(CurrencyId::ForeignAsset(foreign_asset_id)) = Pallet::::location_to_currency_ids(location) { if let Some(asset_metadata) = Pallet::::asset_metadatas(AssetIds::ForeignAssetId(foreign_asset_id)) { let minimum_balance = asset_metadata.minimal_balance.into(); @@ -584,7 +578,7 @@ impl BuyWeightRate for BuyWeightRateOfErc20 where BalanceOf: Into, { - fn calculate_rate(location: MultiLocation) -> Option { + fn calculate_rate(location: MultiLocation) -> Option { match location { MultiLocation { parents: 0, @@ -613,118 +607,6 @@ where } } -/// Simple fee calculator that requires payment in a single fungible at a fixed rate. -/// -/// The constant `FixedRate` type parameter should be the concrete fungible ID and the amount of it -/// required for one second of weight. -pub struct FixedRateOfAssetRegistry, R: TakeRevenue, M: BuyWeightRate> { - weight: Weight, - amount: u128, - ed_ratio: FixedU128, - multi_location: Option, - _marker: PhantomData<(FixedRate, R, M)>, -} - -impl, R: TakeRevenue, M: BuyWeightRate> WeightTrader - for FixedRateOfAssetRegistry -{ - fn new() -> Self { - Self { - weight: 0, - amount: 0, - ed_ratio: Default::default(), - multi_location: None, - _marker: PhantomData, - } - } - - fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result { - log::trace!(target: "asset-registry::weight", "buy_weight weight: {:?}, payment: {:?}", weight, payment); - - // only support first fungible assets now. - let asset_id = payment - .fungible - .iter() - .next() - .map_or(Err(XcmError::TooExpensive), |v| Ok(v.0))?; - - if let AssetId::Concrete(ref multi_location) = asset_id { - log::debug!(target: "asset-registry::weight", "buy_weight multi_location: {:?}", multi_location); - - if let Some(ed_ratio) = M::calculate_rate(multi_location.clone()) { - // The WEIGHT_PER_SECOND is non-zero. - let weight_ratio = FixedU128::saturating_from_rational(weight as u128, WEIGHT_PER_SECOND as u128); - let amount = ed_ratio.saturating_mul_int(weight_ratio.saturating_mul_int(FixedRate::get())); - - let required = MultiAsset { - id: asset_id.clone(), - fun: Fungible(amount), - }; - - log::trace!( - target: "asset-registry::weight", "buy_weight payment: {:?}, required: {:?}, fixed_rate: {:?}, ed_ratio: {:?}, weight_ratio: {:?}", - payment, required, FixedRate::get(), ed_ratio, weight_ratio - ); - let unused = payment - .clone() - .checked_sub(required) - .map_err(|_| XcmError::TooExpensive)?; - self.weight = self.weight.saturating_add(weight); - self.amount = self.amount.saturating_add(amount); - self.ed_ratio = ed_ratio; - self.multi_location = Some(multi_location.clone()); - return Ok(unused); - } - } - - log::trace!(target: "asset-registry::weight", "no concrete fungible asset"); - Err(XcmError::TooExpensive) - } - - fn refund_weight(&mut self, weight: Weight) -> Option { - log::trace!( - target: "asset-registry::weight", "refund_weight weight: {:?}, weight: {:?}, amount: {:?}, ed_ratio: {:?}, multi_location: {:?}", - weight, self.weight, self.amount, self.ed_ratio, self.multi_location - ); - let weight = weight.min(self.weight); - let weight_ratio = FixedU128::saturating_from_rational(weight as u128, WEIGHT_PER_SECOND as u128); - let amount = self - .ed_ratio - .saturating_mul_int(weight_ratio.saturating_mul_int(FixedRate::get())); - - self.weight = self.weight.saturating_sub(weight); - self.amount = self.amount.saturating_sub(amount); - - log::trace!(target: "asset-registry::weight", "refund_weight amount: {:?}", amount); - if amount > 0 && self.multi_location.is_some() { - Some( - ( - self.multi_location.as_ref().expect("checked is non-empty; qed").clone(), - amount, - ) - .into(), - ) - } else { - None - } - } -} - -impl, R: TakeRevenue, M: BuyWeightRate> Drop for FixedRateOfAssetRegistry { - fn drop(&mut self) { - log::trace!(target: "asset-registry::weight", "take revenue, weight: {:?}, amount: {:?}, multi_location: {:?}", self.weight, self.amount, self.multi_location); - if self.amount > 0 && self.multi_location.is_some() { - R::take_revenue( - ( - self.multi_location.as_ref().expect("checked is non-empty; qed").clone(), - self.amount, - ) - .into(), - ); - } - } -} - pub struct EvmErc20InfoMapping(sp_std::marker::PhantomData); impl EvmErc20InfoMapping { diff --git a/modules/support/src/lib.rs b/modules/support/src/lib.rs index 828cf62b55..7982ea3a51 100644 --- a/modules/support/src/lib.rs +++ b/modules/support/src/lib.rs @@ -190,5 +190,5 @@ pub trait NomineesProvider { } pub trait BuyWeightRate { - fn calculate_rate(location: MultiLocation) -> Option; + fn calculate_rate(location: MultiLocation) -> Option; } diff --git a/modules/support/src/mocks.rs b/modules/support/src/mocks.rs index 2488cc6e4c..ddeba2afc6 100644 --- a/modules/support/src/mocks.rs +++ b/modules/support/src/mocks.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . #![allow(clippy::type_complexity)] -use crate::{AddressMapping, BuyWeightRate, CurrencyId, Erc20InfoMapping, Rate, TransactionPayment}; +use crate::{AddressMapping, CurrencyId, Erc20InfoMapping, TransactionPayment}; use codec::Encode; use frame_support::pallet_prelude::{DispatchClass, Pays, Weight}; use nutsfinance_stable_asset::{ @@ -30,12 +30,11 @@ use primitives::{ }; use sp_core::{crypto::AccountId32, H160}; use sp_io::hashing::blake2_256; -use sp_runtime::{traits::One, transaction_validity::TransactionValidityError, DispatchError, DispatchResult}; +use sp_runtime::{transaction_validity::TransactionValidityError, DispatchError, DispatchResult}; use sp_std::{marker::PhantomData, vec::Vec}; #[cfg(feature = "std")] use frame_support::traits::Imbalance; -use xcm::latest::MultiLocation; pub struct MockAddressMapping; @@ -409,17 +408,3 @@ impl StableAsset unimplemented!() } } - -pub struct MockNoneMinimumBalance; -impl BuyWeightRate for MockNoneMinimumBalance { - fn calculate_rate(_: MultiLocation) -> Option { - None - } -} - -pub struct MockFixedMinimumBalance; -impl BuyWeightRate for MockFixedMinimumBalance { - fn calculate_rate(_: MultiLocation) -> Option { - Some(Rate::one()) - } -} diff --git a/modules/transaction-payment/Cargo.toml b/modules/transaction-payment/Cargo.toml index 2d55dec865..ee170eee81 100644 --- a/modules/transaction-payment/Cargo.toml +++ b/modules/transaction-payment/Cargo.toml @@ -20,8 +20,6 @@ support = { package = "module-support", path = "../support", default-features = orml-traits = { path = "../../orml/traits", default-features = false } xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.22", default-features = false } -xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.22", default-features = false } -xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.22", default-features = false } [dev-dependencies] sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" } @@ -48,7 +46,5 @@ std = [ "support/std", "orml-traits/std", "xcm/std", - "xcm-builder/std", - "xcm-executor/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/modules/transaction-payment/src/lib.rs b/modules/transaction-payment/src/lib.rs index 3602c3e936..fe2bafa065 100644 --- a/modules/transaction-payment/src/lib.rs +++ b/modules/transaction-payment/src/lib.rs @@ -36,10 +36,7 @@ use frame_support::{ WithdrawReasons, }, transactional, - weights::{ - constants::WEIGHT_PER_SECOND, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, WeightToFeeCoefficient, - WeightToFeePolynomial, - }, + weights::{DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, WeightToFeeCoefficient, WeightToFeePolynomial}, BoundedVec, PalletId, }; use frame_system::pallet_prelude::*; @@ -59,10 +56,8 @@ use sp_runtime::{ FixedPointNumber, FixedPointOperand, MultiSignature, Percent, Perquintill, }; use sp_std::prelude::*; -use support::{DEXManager, PriceProvider, Ratio, SwapLimit, TransactionPayment}; -use xcm::opaque::latest::{prelude::XcmError, AssetId, Fungibility::Fungible, MultiAsset, MultiLocation}; -use xcm_builder::TakeRevenue; -use xcm_executor::{traits::WeightTrader, Assets}; +use support::{BuyWeightRate, DEXManager, PriceProvider, Ratio, SwapLimit, TransactionPayment}; +use xcm::opaque::latest::MultiLocation; mod mock; mod tests; @@ -1074,94 +1069,17 @@ where } } -/// `WeightTrader` implementation used for `Trader`, the `rate` is read from storage, -/// and `token_per_second` is calculated by `rate` * `native_asset_per_second`. -pub struct TransactionFeePoolTrader, R: TakeRevenue> { - weight: Weight, - amount: u128, - asset_location: Option, - asset_per_second: u128, - _marker: PhantomData<(T, C, K, R)>, -} - -impl, R: TakeRevenue> WeightTrader for TransactionFeePoolTrader +/// Calculate the exchange rate of token in transaction fee pool. +pub struct BuyWeightRateOfTransactionFeePool(sp_std::marker::PhantomData<(T, C)>); +impl BuyWeightRate for BuyWeightRateOfTransactionFeePool where C: Convert>, { - fn new() -> Self { - Self { - weight: 0, - amount: 0, - asset_location: None, - asset_per_second: 0, - _marker: Default::default(), - } - } - - fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result { - // only support first fungible assets now. - let asset_id = payment - .fungible - .iter() - .next() - .map_or(Err(XcmError::TooExpensive), |v| Ok(v.0))?; - - if let AssetId::Concrete(ref multi_location) = asset_id.clone() { - if let Some(token_id) = C::convert(multi_location.clone()) { - if let Some(rate) = TokenExchangeRate::::get(token_id) { - // calculate the amount of fungible asset. - let weight_ratio = Ratio::saturating_from_rational(weight as u128, WEIGHT_PER_SECOND as u128); - let asset_per_second = rate.saturating_mul_int(K::get()); - let amount = weight_ratio.saturating_mul_int(asset_per_second); - let required = MultiAsset { - id: asset_id.clone(), - fun: Fungible(amount), - }; - let unused = payment.checked_sub(required).map_err(|_| XcmError::TooExpensive)?; - self.weight = self.weight.saturating_add(weight); - self.amount = self.amount.saturating_add(amount); - self.asset_location = Some(multi_location.clone()); - self.asset_per_second = asset_per_second; - return Ok(unused); - } - } - } - Err(XcmError::TooExpensive) - } - - fn refund_weight(&mut self, weight: Weight) -> Option { - let weight = weight.min(self.weight); - let weight_ratio = Ratio::saturating_from_rational(weight as u128, WEIGHT_PER_SECOND as u128); - let amount = weight_ratio.saturating_mul_int(self.asset_per_second); - self.weight = self.weight.saturating_sub(weight); - self.amount = self.amount.saturating_sub(amount); - if amount > 0 && self.asset_location.is_some() { - Some( - ( - self.asset_location.as_ref().expect("checked is non-empty; qed").clone(), - amount, - ) - .into(), - ) - } else { - None - } + fn calculate_rate(multi_location: MultiLocation) -> Option { + C::convert(multi_location).and_then(TokenExchangeRate::::get) } } -impl, R: TakeRevenue> Drop for TransactionFeePoolTrader { - fn drop(&mut self) { - if self.amount > 0 && self.asset_location.is_some() { - R::take_revenue( - ( - self.asset_location.as_ref().expect("checked is non-empty; qed").clone(), - self.amount, - ) - .into(), - ); - } - } -} impl Convert> for Pallet where T: Config, diff --git a/modules/transaction-payment/src/tests.rs b/modules/transaction-payment/src/tests.rs index c206aa0893..5c20c3884a 100644 --- a/modules/transaction-payment/src/tests.rs +++ b/modules/transaction-payment/src/tests.rs @@ -23,7 +23,7 @@ use super::*; use crate::mock::{AlternativeFeeSurplus, AusdFeeSwapPath, CustomFeeSurplus, DotFeeSwapPath}; use frame_support::{ - assert_noop, assert_ok, parameter_types, + assert_noop, assert_ok, weights::{DispatchClass, DispatchInfo, Pays}, }; use mock::{ @@ -39,10 +39,9 @@ use sp_runtime::{ testing::TestXt, traits::{One, UniqueSaturatedInto}, }; -use support::{Price, TransactionPayment as TransactionPaymentT}; +use support::{BuyWeightRate, Price, TransactionPayment as TransactionPaymentT}; use xcm::latest::prelude::*; use xcm::prelude::GeneralKey; -use xcm_executor::Assets; const CALL: ::Call = Call::Currencies(module_currencies::Call::transfer { dest: BOB, @@ -1363,35 +1362,23 @@ impl Convert> for CurrencyIdConvert { } #[test] -fn period_rate_buy_refund_weight_works() { - parameter_types! { - pub const NativePerSecond: u128 = 8_000_000_000_000; - } +fn buy_weight_transaction_fee_pool_works() { builder_with_dex_and_fee_pool(true).execute_with(|| { - let mock_weight: Weight = 200_000_000; - let dot_rate = TokenExchangeRate::::get(DOT); - let usd_rate = TokenExchangeRate::::get(AUSD); - assert_eq!(dot_rate, Some(Ratio::saturating_from_rational(1, 10))); - assert_eq!(usd_rate, Some(Ratio::saturating_from_rational(10, 1))); - - // 1DOT=10KAR, rate=DOT/KAR=1/10, rate=0.1, amount=rate*kar_per_second*weight, - // amount=8*weight*rate=0.8*weight=160_000_000 - let asset: MultiAsset = ((0, X1(GeneralKey(DOT.encode()))), 170_000_000).into(); - let assets: Assets = asset.into(); - let mut trader = TransactionFeePoolTrader::::new(); - let unused = trader.buy_weight(mock_weight, assets); - let expect_asset: MultiAsset = ((0, X1(GeneralKey(DOT.encode()))), 10_000_000).into(); - assert_eq!(unused.unwrap(), expect_asset.into()); - assert_eq!(trader.amount, 160_000_000); - - // 1KAR=10AUSD, rate=AUSD/KAR=10, rate=10, amount=8*weight*rate=80*weight=16_000_000_000 - let asset: MultiAsset = ((0, X1(GeneralKey(AUSD.encode()))), 17_000_000_000).into(); - let assets: Assets = asset.into(); - let mut trader = TransactionFeePoolTrader::::new(); - let unused = trader.buy_weight(mock_weight, assets); - let expect_asset: MultiAsset = ((0, X1(GeneralKey(AUSD.encode()))), 1_000_000_000).into(); - assert_eq!(unused.unwrap(), expect_asset.into()); - assert_eq!(trader.amount, 16_000_000_000); + // Location convert return None. + let location = MultiLocation::new(1, X1(Junction::Parachain(2000))); + let rate = >::calculate_rate(location); + assert_eq!(rate, None); + + // Token not in charge fee pool + let currency_id = CurrencyId::Token(TokenSymbol::LDOT); + let location = MultiLocation::new(1, X1(GeneralKey(currency_id.encode()))); + let rate = >::calculate_rate(location); + assert_eq!(rate, None); + + // DOT Token is in charge fee pool. + let location = MultiLocation::parent(); + let rate = >::calculate_rate(location); + assert_eq!(rate, Some(Ratio::saturating_from_rational(1, 10))); }); } diff --git a/primitives/src/unchecked_extrinsic.rs b/primitives/src/unchecked_extrinsic.rs index 5fc37ed93a..a187aed108 100644 --- a/primitives/src/unchecked_extrinsic.rs +++ b/primitives/src/unchecked_extrinsic.rs @@ -37,22 +37,22 @@ use sp_runtime::{ use sp_std::{marker::PhantomData, prelude::*}; #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] -#[scale_info(skip_type_params(ConvertTx, CheckPayerTx))] +#[scale_info(skip_type_params(ConvertEthTx, CheckPayerTx))] pub struct AcalaUncheckedExtrinsic< Call, Extra: SignedExtension, - ConvertTx, + ConvertEthTx, StorageDepositPerByte, TxFeePerGas, CheckPayerTx, >( pub UncheckedExtrinsic, - PhantomData<(ConvertTx, StorageDepositPerByte, TxFeePerGas, CheckPayerTx)>, + PhantomData<(ConvertEthTx, StorageDepositPerByte, TxFeePerGas, CheckPayerTx)>, ); #[cfg(feature = "std")] -impl parity_util_mem::MallocSizeOf - for AcalaUncheckedExtrinsic +impl parity_util_mem::MallocSizeOf + for AcalaUncheckedExtrinsic where Extra: SignedExtension, { @@ -62,8 +62,8 @@ where } } -impl Extrinsic - for AcalaUncheckedExtrinsic +impl Extrinsic + for AcalaUncheckedExtrinsic { type Call = Call; @@ -85,27 +85,27 @@ impl ExtrinsicMetadata - for AcalaUncheckedExtrinsic +impl ExtrinsicMetadata + for AcalaUncheckedExtrinsic { const VERSION: u8 = UncheckedExtrinsic::::VERSION; type SignedExtensions = Extra; } -impl ExtrinsicCall - for AcalaUncheckedExtrinsic +impl ExtrinsicCall + for AcalaUncheckedExtrinsic { fn call(&self) -> &Self::Call { self.0.call() } } -impl Checkable - for AcalaUncheckedExtrinsic +impl Checkable + for AcalaUncheckedExtrinsic where Call: Encode + Member, Extra: SignedExtension, - ConvertTx: Convert<(Call, Extra), Result<(EthereumTransactionMessage, Extra), InvalidTransaction>>, + ConvertEthTx: Convert<(Call, Extra), Result<(EthereumTransactionMessage, Extra), InvalidTransaction>>, CheckPayerTx: Convert<(Call, Extra), Result<(), InvalidTransaction>>, StorageDepositPerByte: Get, TxFeePerGas: Get, @@ -122,7 +122,7 @@ where match self.0.signature { Some((addr, AcalaMultiSignature::Ethereum(sig), extra)) => { - let (eth_msg, eth_extra) = ConvertTx::convert((function.clone(), extra))?; + let (eth_msg, eth_extra) = ConvertEthTx::convert((function.clone(), extra))?; log::trace!( target: "evm", "Ethereum eth_msg: {:?}", eth_msg ); @@ -171,7 +171,7 @@ where }) } Some((addr, AcalaMultiSignature::Eip1559(sig), extra)) => { - let (eth_msg, eth_extra) = ConvertTx::convert((function.clone(), extra))?; + let (eth_msg, eth_extra) = ConvertEthTx::convert((function.clone(), extra))?; log::trace!( target: "evm", "Eip1559 eth_msg: {:?}", eth_msg ); @@ -215,7 +215,7 @@ where }) } Some((addr, AcalaMultiSignature::AcalaEip712(sig), extra)) => { - let (eth_msg, eth_extra) = ConvertTx::convert((function.clone(), extra))?; + let (eth_msg, eth_extra) = ConvertEthTx::convert((function.clone(), extra))?; log::trace!( target: "evm", "AcalaEip712 eth_msg: {:?}", eth_msg ); @@ -239,8 +239,8 @@ where } } -impl GetDispatchInfo - for AcalaUncheckedExtrinsic +impl GetDispatchInfo + for AcalaUncheckedExtrinsic where Call: GetDispatchInfo, Extra: SignedExtension, @@ -251,8 +251,9 @@ where } #[cfg(feature = "std")] -impl serde::Serialize - for AcalaUncheckedExtrinsic +impl + serde::Serialize + for AcalaUncheckedExtrinsic { fn serialize(&self, seq: S) -> Result where @@ -263,9 +264,9 @@ impl +impl<'a, Call: Decode, Extra: SignedExtension, ConvertEthTx, StorageDepositPerByte, TxFeePerGas, CheckPayerTx> serde::Deserialize<'a> - for AcalaUncheckedExtrinsic + for AcalaUncheckedExtrinsic { fn deserialize(de: D) -> Result where diff --git a/runtime/acala/src/lib.rs b/runtime/acala/src/lib.rs index a32b89e71d..450078a8d1 100644 --- a/runtime/acala/src/lib.rs +++ b/runtime/acala/src/lib.rs @@ -50,14 +50,14 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; use frame_system::{EnsureRoot, RawOrigin}; -use module_asset_registry::{AssetIdMaps, EvmErc20InfoMapping, FixedRateOfAssetRegistry}; +use module_asset_registry::{AssetIdMaps, EvmErc20InfoMapping}; use module_cdp_engine::CollateralCurrencyIds; use module_currencies::BasicCurrencyAdapter; use module_evm::{runner::RunnerExtended, CallInfo, CreateInfo, EvmChainId, EvmTask}; use module_evm_accounts::EvmAddressMapping; use module_relaychain::RelayChainCallBuilder; use module_support::{AssetIdMapping, DispatchableTask}; -use module_transaction_payment::{TargetedFeeAdjustment, TransactionFeePoolTrader}; +use module_transaction_payment::TargetedFeeAdjustment; use cumulus_pallet_parachain_system::RelaychainBlockNumberProvider; use orml_traits::{ @@ -99,15 +99,15 @@ pub use primitives::{ TradingPair, }; pub use runtime_common::{ - calculate_asset_ratio, cent, dollar, microcent, millicent, AcalaDropAssets, AllPrecompiles, - EnsureRootOrAllGeneralCouncil, EnsureRootOrAllTechnicalCommittee, EnsureRootOrHalfFinancialCouncil, - EnsureRootOrHalfGeneralCouncil, EnsureRootOrHalfHomaCouncil, EnsureRootOrOneGeneralCouncil, - EnsureRootOrOneThirdsTechnicalCommittee, EnsureRootOrThreeFourthsGeneralCouncil, - EnsureRootOrTwoThirdsGeneralCouncil, EnsureRootOrTwoThirdsTechnicalCommittee, ExchangeRate, - ExistentialDepositsTimesOneHundred, FinancialCouncilInstance, FinancialCouncilMembershipInstance, GasToWeight, - GeneralCouncilInstance, GeneralCouncilMembershipInstance, HomaCouncilInstance, HomaCouncilMembershipInstance, - MaxTipsOfPriority, OffchainSolutionWeightLimit, OperationalFeeMultiplier, OperatorMembershipInstanceAcala, Price, - ProxyType, Rate, Ratio, RuntimeBlockLength, RuntimeBlockWeights, SystemContractsFilter, TechnicalCommitteeInstance, + cent, dollar, microcent, millicent, AcalaDropAssets, AllPrecompiles, EnsureRootOrAllGeneralCouncil, + EnsureRootOrAllTechnicalCommittee, EnsureRootOrHalfFinancialCouncil, EnsureRootOrHalfGeneralCouncil, + EnsureRootOrHalfHomaCouncil, EnsureRootOrOneGeneralCouncil, EnsureRootOrOneThirdsTechnicalCommittee, + EnsureRootOrThreeFourthsGeneralCouncil, EnsureRootOrTwoThirdsGeneralCouncil, + EnsureRootOrTwoThirdsTechnicalCommittee, ExchangeRate, ExistentialDepositsTimesOneHundred, + FinancialCouncilInstance, FinancialCouncilMembershipInstance, GasToWeight, GeneralCouncilInstance, + GeneralCouncilMembershipInstance, HomaCouncilInstance, HomaCouncilMembershipInstance, MaxTipsOfPriority, + OffchainSolutionWeightLimit, OperationalFeeMultiplier, OperatorMembershipInstanceAcala, Price, ProxyType, Rate, + Ratio, RuntimeBlockLength, RuntimeBlockWeights, SystemContractsFilter, TechnicalCommitteeInstance, TechnicalCommitteeMembershipInstance, TimeStampedPrice, TipPerWeightStep, ACA, AUSD, DOT, LCDOT, LDOT, RENBTC, }; pub use xcm::latest::prelude::*; @@ -2126,50 +2126,50 @@ impl Convert<(Call, SignedExtra), Result<(EthereumTransactionMessage, SignedExtr fn convert( (call, mut extra): (Call, SignedExtra), ) -> Result<(EthereumTransactionMessage, SignedExtra), InvalidTransaction> { - match call { - Call::EVM(module_evm::Call::eth_call { - action, - input, - value, - gas_limit, - storage_limit, - access_list, - valid_until, - }) => { - if System::block_number() > valid_until { - return Err(InvalidTransaction::Stale); - } - - let (_, _, _, _, mortality, check_nonce, _, charge, ..) = extra.clone(); + if let Call::EVM(module_evm::Call::eth_call { + action, + input, + value, + gas_limit, + storage_limit, + access_list, + valid_until, + }) = call + { + if System::block_number() > valid_until { + return Err(InvalidTransaction::Stale); + } - if mortality != frame_system::CheckEra::from(sp_runtime::generic::Era::Immortal) { - // require immortal - return Err(InvalidTransaction::BadProof); - } + let (_, _, _, _, mortality, check_nonce, _, charge, ..) = extra.clone(); - let nonce = check_nonce.nonce; - let tip = charge.0; - - extra.5.mark_as_ethereum_tx(valid_until); - - Ok(( - EthereumTransactionMessage { - chain_id: EVM::chain_id(), - genesis: System::block_hash(0), - nonce, - tip, - gas_limit, - storage_limit, - action, - value, - input, - valid_until, - access_list, - }, - extra, - )) + if mortality != frame_system::CheckEra::from(sp_runtime::generic::Era::Immortal) { + // require immortal + return Err(InvalidTransaction::BadProof); } - _ => Err(InvalidTransaction::BadProof), + + let nonce = check_nonce.nonce; + let tip = charge.0; + + extra.5.mark_as_ethereum_tx(valid_until); + + Ok(( + EthereumTransactionMessage { + chain_id: EVM::chain_id(), + genesis: System::block_hash(0), + nonce, + tip, + gas_limit, + storage_limit, + action, + value, + input, + valid_until, + access_list, + }, + extra, + )) + } else { + Err(InvalidTransaction::BadProof) } } } diff --git a/runtime/acala/src/xcm_config.rs b/runtime/acala/src/xcm_config.rs index 074d64e341..22820f35c8 100644 --- a/runtime/acala/src/xcm_config.rs +++ b/runtime/acala/src/xcm_config.rs @@ -18,9 +18,8 @@ use super::{ constants::fee::*, AcalaTreasuryAccount, AccountId, AssetIdMapping, AssetIdMaps, Balance, Call, Convert, - Currencies, CurrencyId, Event, ExistentialDeposits, FixedRateOfAssetRegistry, GetNativeCurrencyId, - NativeTokenExistentialDeposit, Origin, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, - TransactionFeePoolTrader, UnknownTokens, XcmpQueue, ACA, AUSD, + Currencies, CurrencyId, Event, ExistentialDeposits, GetNativeCurrencyId, NativeTokenExistentialDeposit, Origin, + ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, UnknownTokens, XcmpQueue, ACA, AUSD, }; use codec::{Decode, Encode}; pub use cumulus_primitives_core::ParaId; @@ -30,12 +29,13 @@ pub use frame_support::{ weights::Weight, }; use module_asset_registry::{BuyWeightRateOfErc20, BuyWeightRateOfForeignAsset}; +use module_transaction_payment::BuyWeightRateOfTransactionFeePool; use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key, MultiCurrency}; use orml_xcm_support::{DepositToAlternative, IsNativeConcrete, MultiCurrencyAdapter, MultiNativeAsset}; use pallet_xcm::XcmPassthrough; use polkadot_parachain::primitives::Sibling; use primitives::evm::is_system_contract; -use runtime_common::{AcalaDropAssets, EnsureRootOrHalfGeneralCouncil}; +use runtime_common::{native_currency_location, AcalaDropAssets, EnsureRootOrHalfGeneralCouncil, FixedRateOfAsset}; use xcm::latest::prelude::*; pub use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, @@ -133,17 +133,16 @@ parameter_types! { ).into(), aca_per_second() ); - pub ForeignAssetUnitsPerSecond: u128 = aca_per_second(); - pub AcaPerSecondAsBased: u128 = aca_per_second(); + pub BaseRate: u128 = aca_per_second(); } pub type Trader = ( - TransactionFeePoolTrader, + FixedRateOfAsset>, FixedRateOfFungible, FixedRateOfFungible, FixedRateOfFungible, - FixedRateOfAssetRegistry>, - FixedRateOfAssetRegistry>, + FixedRateOfAsset>, + FixedRateOfAsset>, ); pub struct XcmConfig; @@ -234,11 +233,6 @@ pub type LocalAssetTransactor = MultiCurrencyAdapter< DepositToAlternative, >; -//TODO: use token registry currency type encoding -fn native_currency_location(id: CurrencyId) -> MultiLocation { - MultiLocation::new(1, X2(Parachain(ParachainInfo::get().into()), GeneralKey(id.encode()))) -} - pub struct CurrencyIdConvert; impl Convert> for CurrencyIdConvert { fn convert(id: CurrencyId) -> Option { @@ -246,8 +240,10 @@ impl Convert> for CurrencyIdConvert { use CurrencyId::{Erc20, ForeignAsset, Token}; match id { Token(DOT) => Some(MultiLocation::parent()), - Token(ACA) | Token(AUSD) | Token(LDOT) => Some(native_currency_location(id)), - Erc20(address) if !is_system_contract(address) => Some(native_currency_location(id)), + Token(ACA) | Token(AUSD) | Token(LDOT) => Some(native_currency_location(ParachainInfo::get().into(), id)), + Erc20(address) if !is_system_contract(address) => { + Some(native_currency_location(ParachainInfo::get().into(), id)) + } ForeignAsset(foreign_asset_id) => AssetIdMaps::::get_multi_location(foreign_asset_id), _ => None, } diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml index b191a0d5c0..693fa11576 100644 --- a/runtime/common/Cargo.toml +++ b/runtime/common/Cargo.toml @@ -12,6 +12,7 @@ required-features = ["bench"] [dependencies] hex-literal = "0.3.1" static_assertions = "1.1.0" +log = { version = "0.4.17", default-features = false } num_enum = { version = "0.5.1", default-features = false } serde = { version = "1.0.136", optional = true, default-features = false } serde_json = { version = "1.0.68", default-features = false, features = ["alloc"] } @@ -76,6 +77,7 @@ orml-currencies = { path = "../../orml/currencies", default-features = false, op default = ["std"] std = [ "num_enum/std", + "log/std", "serde", "serde_json/std", "codec/std", diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index 8a81bb0c8f..38b068efbd 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -22,10 +22,9 @@ #![recursion_limit = "256"] use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::traits::Get; use frame_support::{ parameter_types, - traits::{Contains, EnsureOneOf}, + traits::{Contains, EnsureOneOf, Get}, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, WEIGHT_PER_MILLIS}, DispatchClass, Weight, @@ -33,29 +32,17 @@ use frame_support::{ RuntimeDebug, }; use frame_system::{limits, EnsureRoot}; -pub use module_support::{ExchangeRate, PrecompileCallerFilter, Price, Rate, Ratio}; +use module_evm::GenesisAccount; +use orml_traits::GetByKey; use primitives::{evm::is_system_contract, Balance, CurrencyId, Nonce}; use scale_info::TypeInfo; use sp_core::{Bytes, H160}; -use sp_runtime::{traits::Convert, transaction_validity::TransactionPriority, FixedPointNumber, Perbill}; -use sp_std::collections::btree_map::BTreeMap; +use sp_runtime::{traits::Convert, transaction_validity::TransactionPriority, Perbill}; +use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, prelude::*}; use static_assertions::const_assert; -#[cfg(feature = "std")] -use sp_core::bytes::from_hex; -#[cfg(feature = "std")] -use std::str::FromStr; - -pub mod bench; -pub mod check_nonce; -pub mod precompile; - -#[cfg(test)] -mod mock; - pub use check_nonce::CheckNonce; -use module_evm::GenesisAccount; -use orml_traits::GetByKey; +pub use module_support::{ExchangeRate, PrecompileCallerFilter, Price, Rate, Ratio}; pub use precompile::{ AllPrecompiles, DEXPrecompile, EVMPrecompile, MultiCurrencyPrecompile, NFTPrecompile, OraclePrecompile, SchedulePrecompile, StableAssetPrecompile, @@ -64,12 +51,21 @@ pub use primitives::{ currency::{TokenInfo, ACA, AUSD, BNC, DOT, KAR, KBTC, KINT, KSM, KUSD, LCDOT, LDOT, LKSM, PHA, RENBTC, VSKSM}, AccountId, }; -use sp_std::{marker::PhantomData, prelude::*}; -pub use xcm::latest::prelude::*; -pub use xcm_builder::TakeRevenue; -pub use xcm_executor::{traits::DropAssets, Assets}; +pub use xcm_impl::{native_currency_location, AcalaDropAssets, FixedRateOfAsset}; + +#[cfg(feature = "std")] +use sp_core::bytes::from_hex; +#[cfg(feature = "std")] +use std::str::FromStr; + +pub mod bench; +pub mod check_nonce; +pub mod precompile; +pub mod xcm_impl; mod gas_to_weight_ratio; +#[cfg(test)] +mod mock; pub type TimeStampedPrice = orml_oracle::TimestampedValue; @@ -205,10 +201,6 @@ pub fn microcent(currency_id: CurrencyId) -> Balance { millicent(currency_id) / 1000 } -pub fn calculate_asset_ratio(foreign_asset: (AssetId, u128), native_asset: (AssetId, u128)) -> Ratio { - Ratio::saturating_from_rational(foreign_asset.1, native_asset.1) -} - pub type GeneralCouncilInstance = pallet_collective::Instance1; pub type FinancialCouncilInstance = pallet_collective::Instance2; pub type HomaCouncilInstance = pallet_collective::Instance3; @@ -347,77 +339,6 @@ impl Default for ProxyType { } } -pub fn native_currency_location(para_id: u32, id: CurrencyId) -> MultiLocation { - MultiLocation::new(1, X2(Parachain(para_id), GeneralKey(id.encode()))) -} - -/// `DropAssets` implementation support asset amount lower thant ED handled by `TakeRevenue`. -/// -/// parameters type: -/// - `NC`: native currency_id type. -/// - `NB`: the ExistentialDeposit amount of native currency_id. -/// - `GK`: the ExistentialDeposit amount of tokens. -pub struct AcalaDropAssets(PhantomData<(X, T, C, NC, NB, GK)>); -impl DropAssets for AcalaDropAssets -where - X: DropAssets, - T: TakeRevenue, - C: Convert>, - NC: Get, - NB: Get, - GK: GetByKey, -{ - fn drop_assets(origin: &MultiLocation, assets: Assets) -> Weight { - let multi_assets: Vec = assets.into(); - let mut asset_traps: Vec = vec![]; - for asset in multi_assets { - if let MultiAsset { - id: Concrete(location), - fun: Fungible(amount), - } = asset.clone() - { - let currency_id = C::convert(location); - // burn asset(do nothing here) if convert result is None - if let Some(currency_id) = currency_id { - let ed = ExistentialDepositsForDropAssets::::get(¤cy_id); - if amount < ed { - T::take_revenue(asset); - } else { - asset_traps.push(asset); - } - } - } - } - if !asset_traps.is_empty() { - X::drop_assets(origin, asset_traps.into()); - } - 0 - } -} - -/// `ExistentialDeposit` for tokens, give priority to match native token, then handled by -/// `ExistentialDeposits`. -/// -/// parameters type: -/// - `NC`: native currency_id type. -/// - `NB`: the ExistentialDeposit amount of native currency_id. -/// - `GK`: the ExistentialDeposit amount of tokens. -pub struct ExistentialDepositsForDropAssets(PhantomData<(NC, NB, GK)>); -impl ExistentialDepositsForDropAssets -where - NC: Get, - NB: Get, - GK: GetByKey, -{ - fn get(currency_id: &CurrencyId) -> Balance { - if currency_id == &NC::get() { - NB::get() - } else { - GK::get(currency_id) - } - } -} - pub struct EvmLimits(PhantomData); impl EvmLimits where diff --git a/runtime/common/src/xcm_impl.rs b/runtime/common/src/xcm_impl.rs new file mode 100644 index 0000000000..44f03b0473 --- /dev/null +++ b/runtime/common/src/xcm_impl.rs @@ -0,0 +1,264 @@ +// This file is part of Acala. + +// Copyright (C) 2020-2022 Acala Foundation. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Common xcm implementation + +use codec::Encode; +use frame_support::{ + traits::Get, + weights::{constants::WEIGHT_PER_SECOND, Weight}, +}; +use module_support::BuyWeightRate; +use orml_traits::GetByKey; +use primitives::{Balance, CurrencyId}; +use sp_runtime::{traits::Convert, FixedPointNumber, FixedU128}; +use sp_std::{marker::PhantomData, prelude::*}; +use xcm::latest::prelude::*; +use xcm_builder::TakeRevenue; +use xcm_executor::{ + traits::{DropAssets, WeightTrader}, + Assets, +}; + +pub fn native_currency_location(para_id: u32, id: CurrencyId) -> MultiLocation { + MultiLocation::new(1, X2(Parachain(para_id), GeneralKey(id.encode()))) +} + +/// `ExistentialDeposit` for tokens, give priority to match native token, then handled by +/// `ExistentialDeposits`. +/// +/// parameters type: +/// - `NC`: native currency_id type. +/// - `NB`: the ExistentialDeposit amount of native currency_id. +/// - `GK`: the ExistentialDeposit amount of tokens. +pub struct ExistentialDepositsForDropAssets(PhantomData<(NC, NB, GK)>); +impl ExistentialDepositsForDropAssets +where + NC: Get, + NB: Get, + GK: GetByKey, +{ + fn get(currency_id: &CurrencyId) -> Balance { + if currency_id == &NC::get() { + NB::get() + } else { + GK::get(currency_id) + } + } +} + +/// `DropAssets` implementation support asset amount lower thant ED handled by `TakeRevenue`. +/// +/// parameters type: +/// - `NC`: native currency_id type. +/// - `NB`: the ExistentialDeposit amount of native currency_id. +/// - `GK`: the ExistentialDeposit amount of tokens. +pub struct AcalaDropAssets(PhantomData<(X, T, C, NC, NB, GK)>); +impl DropAssets for AcalaDropAssets +where + X: DropAssets, + T: TakeRevenue, + C: Convert>, + NC: Get, + NB: Get, + GK: GetByKey, +{ + fn drop_assets(origin: &MultiLocation, assets: Assets) -> Weight { + let multi_assets: Vec = assets.into(); + let mut asset_traps: Vec = vec![]; + for asset in multi_assets { + if let MultiAsset { + id: Concrete(location), + fun: Fungible(amount), + } = asset.clone() + { + let currency_id = C::convert(location); + // burn asset(do nothing here) if convert result is None + if let Some(currency_id) = currency_id { + let ed = ExistentialDepositsForDropAssets::::get(¤cy_id); + if amount < ed { + T::take_revenue(asset); + } else { + asset_traps.push(asset); + } + } + } + } + if !asset_traps.is_empty() { + X::drop_assets(origin, asset_traps.into()); + } + 0 + } +} + +/// Simple fee calculator that requires payment in a single fungible at a fixed rate. +/// +/// - The `FixedRate` constant should be the concrete fungible ID and the amount of it +/// required for one second of weight. +/// - The `TakeRevenue` trait is used to collecting xcm execution fee. +/// - The `BuyWeightRate` trait is used to calculate ratio by location. +pub struct FixedRateOfAsset, R: TakeRevenue, M: BuyWeightRate> { + weight: Weight, + amount: u128, + ratio: FixedU128, + multi_location: Option, + _marker: PhantomData<(FixedRate, R, M)>, +} + +impl, R: TakeRevenue, M: BuyWeightRate> WeightTrader for FixedRateOfAsset { + fn new() -> Self { + Self { + weight: 0, + amount: 0, + ratio: Default::default(), + multi_location: None, + _marker: PhantomData, + } + } + + fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result { + log::trace!(target: "xcm::weight", "buy_weight weight: {:?}, payment: {:?}", weight, payment); + + // only support first fungible assets now. + let asset_id = payment + .fungible + .iter() + .next() + .map_or(Err(XcmError::TooExpensive), |v| Ok(v.0))?; + + if let AssetId::Concrete(ref multi_location) = asset_id { + log::debug!(target: "xcm::weight", "buy_weight multi_location: {:?}", multi_location); + + if let Some(ratio) = M::calculate_rate(multi_location.clone()) { + // The WEIGHT_PER_SECOND is non-zero. + let weight_ratio = FixedU128::saturating_from_rational(weight as u128, WEIGHT_PER_SECOND as u128); + let amount = ratio.saturating_mul_int(weight_ratio.saturating_mul_int(FixedRate::get())); + + let required = MultiAsset { + id: asset_id.clone(), + fun: Fungible(amount), + }; + + log::trace!( + target: "xcm::weight", "buy_weight payment: {:?}, required: {:?}, fixed_rate: {:?}, ratio: {:?}, weight_ratio: {:?}", + payment, required, FixedRate::get(), ratio, weight_ratio + ); + let unused = payment + .clone() + .checked_sub(required) + .map_err(|_| XcmError::TooExpensive)?; + self.weight = self.weight.saturating_add(weight); + self.amount = self.amount.saturating_add(amount); + self.ratio = ratio; + self.multi_location = Some(multi_location.clone()); + return Ok(unused); + } + } + + log::trace!(target: "xcm::weight", "no concrete fungible asset"); + Err(XcmError::TooExpensive) + } + + fn refund_weight(&mut self, weight: Weight) -> Option { + log::trace!( + target: "xcm::weight", "refund_weight weight: {:?}, weight: {:?}, amount: {:?}, ratio: {:?}, multi_location: {:?}", + weight, self.weight, self.amount, self.ratio, self.multi_location + ); + let weight = weight.min(self.weight); + let weight_ratio = FixedU128::saturating_from_rational(weight as u128, WEIGHT_PER_SECOND as u128); + let amount = self + .ratio + .saturating_mul_int(weight_ratio.saturating_mul_int(FixedRate::get())); + + self.weight = self.weight.saturating_sub(weight); + self.amount = self.amount.saturating_sub(amount); + + log::trace!(target: "xcm::weight", "refund_weight amount: {:?}", amount); + if amount > 0 && self.multi_location.is_some() { + Some( + ( + self.multi_location.as_ref().expect("checked is non-empty; qed").clone(), + amount, + ) + .into(), + ) + } else { + None + } + } +} + +impl, R: TakeRevenue, M: BuyWeightRate> Drop for FixedRateOfAsset { + fn drop(&mut self) { + log::trace!(target: "xcm::weight", "take revenue, weight: {:?}, amount: {:?}, multi_location: {:?}", self.weight, self.amount, self.multi_location); + if self.amount > 0 && self.multi_location.is_some() { + R::take_revenue( + ( + self.multi_location.as_ref().expect("checked is non-empty; qed").clone(), + self.amount, + ) + .into(), + ); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::new_test_ext; + use frame_support::{assert_noop, assert_ok, parameter_types}; + use module_support::Ratio; + use sp_runtime::traits::One; + + pub struct MockNoneBuyWeightRate; + impl BuyWeightRate for MockNoneBuyWeightRate { + fn calculate_rate(_: MultiLocation) -> Option { + None + } + } + + pub struct MockFixedBuyWeightRate>(PhantomData); + impl> BuyWeightRate for MockFixedBuyWeightRate { + fn calculate_rate(_: MultiLocation) -> Option { + Some(T::get()) + } + } + + parameter_types! { + const FixedBasedRate: u128 = 10; + FixedRate: Ratio = Ratio::one(); + } + + #[test] + fn buy_weight_rate_mock_works() { + new_test_ext().execute_with(|| { + let asset: MultiAsset = (Parent, 100).into(); + let assets: Assets = asset.into(); + let mut trader = >::new(); + let buy_weight = trader.buy_weight(WEIGHT_PER_SECOND, assets.clone()); + assert_noop!(buy_weight, XcmError::TooExpensive); + + let mut trader = >>::new(); + let buy_weight = trader.buy_weight(WEIGHT_PER_SECOND, assets.clone()); + let asset: MultiAsset = (Parent, 90).into(); + let assets: Assets = asset.into(); + assert_ok!(buy_weight, assets.clone()); + }); + } +} diff --git a/runtime/integration-tests/src/payment.rs b/runtime/integration-tests/src/payment.rs index da6c5054d0..6468a42829 100644 --- a/runtime/integration-tests/src/payment.rs +++ b/runtime/integration-tests/src/payment.rs @@ -257,7 +257,7 @@ fn trader_works() { let unspent: Vec = result_assets.into(); assert_eq!(vec![expect_unspent.clone()], unspent); - let mut period_trader = PeriodTrader::new(); + let mut period_trader = TransactionFeePoolTrader::new(); let result_assets = period_trader.buy_weight(xcm_weight, assets.clone()); assert!(result_assets.is_err()); }); @@ -331,7 +331,7 @@ fn trader_works() { let expect_unspent: MultiAsset = (Parent, total_balance - spent as u128).into(); // the newly `TransactionFeePoolTrader` works fine as first priority - let mut period_trader = PeriodTrader::new(); + let mut period_trader = TransactionFeePoolTrader::new(); let result_assets = period_trader.buy_weight(xcm_weight, assets); let unspent: Vec = result_assets.unwrap().into(); assert_eq!(vec![expect_unspent.clone()], unspent); diff --git a/runtime/integration-tests/src/setup.rs b/runtime/integration-tests/src/setup.rs index 8ae3a0e69c..3814cb84d0 100644 --- a/runtime/integration-tests/src/setup.rs +++ b/runtime/integration-tests/src/setup.rs @@ -59,7 +59,8 @@ mod mandala_imports { Tokens, TransactionPayment, TransactionPaymentPalletId, TreasuryAccount, TreasuryPalletId, UncheckedExtrinsic, Utility, Vesting, XcmInterface, EVM, NFT, }; - pub use runtime_common::{cent, dollar, millicent, ACA, AUSD, DOT, KSM, LDOT, LKSM}; + use module_transaction_payment::BuyWeightRateOfTransactionFeePool; + pub use runtime_common::{cent, dollar, millicent, FixedRateOfAsset, ACA, AUSD, DOT, KSM, LDOT, LKSM}; pub use sp_runtime::traits::AccountIdConversion; use sp_runtime::Percent; pub use xcm_executor::XcmExecutor; @@ -74,8 +75,8 @@ mod mandala_imports { ); pub const NATIVE_TOKEN_SYMBOL: TokenSymbol = TokenSymbol::ACA; pub type Trader = FixedRateOfFungible; - pub type PeriodTrader = - module_transaction_payment::TransactionFeePoolTrader; + pub type TransactionFeePoolTrader = + FixedRateOfAsset>; pub const ALTERNATIVE_SURPLUS: Percent = AlternativeFeeSurplus::get(); } @@ -98,8 +99,9 @@ mod karura_imports { TransactionPayment, TransactionPaymentPalletId, TreasuryPalletId, Utility, Vesting, XTokens, XcmInterface, EVM, NFT, }; + use module_transaction_payment::BuyWeightRateOfTransactionFeePool; pub use primitives::TradingPair; - pub use runtime_common::{calculate_asset_ratio, cent, dollar, millicent, KAR, KSM, KUSD, LKSM}; + pub use runtime_common::{cent, dollar, millicent, FixedRateOfAsset, KAR, KSM, KUSD, LKSM}; pub use sp_runtime::traits::AccountIdConversion; use sp_runtime::Percent; pub use xcm_executor::XcmExecutor; @@ -124,8 +126,8 @@ mod karura_imports { ); pub const NATIVE_TOKEN_SYMBOL: TokenSymbol = TokenSymbol::KAR; pub type Trader = FixedRateOfFungible; - pub type PeriodTrader = - module_transaction_payment::TransactionFeePoolTrader; + pub type TransactionFeePoolTrader = + FixedRateOfAsset>; pub const ALTERNATIVE_SURPLUS: Percent = AlternativeFeeSurplus::get(); } @@ -147,8 +149,9 @@ mod acala_imports { TransactionPaymentPalletId, TreasuryPalletId, Utility, Vesting, XTokens, XcmInterface, EVM, LCDOT, NFT, }; pub use frame_support::parameter_types; + use module_transaction_payment::BuyWeightRateOfTransactionFeePool; pub use primitives::TradingPair; - pub use runtime_common::{cent, dollar, millicent, ACA, AUSD, DOT, LDOT}; + pub use runtime_common::{cent, dollar, millicent, FixedRateOfAsset, ACA, AUSD, DOT, LDOT}; pub use sp_runtime::traits::AccountIdConversion; use sp_runtime::Percent; pub use xcm_executor::XcmExecutor; @@ -175,8 +178,8 @@ mod acala_imports { ); pub const NATIVE_TOKEN_SYMBOL: TokenSymbol = TokenSymbol::ACA; pub type Trader = FixedRateOfFungible; - pub type PeriodTrader = - module_transaction_payment::TransactionFeePoolTrader; + pub type TransactionFeePoolTrader = + FixedRateOfAsset>; pub const ALTERNATIVE_SURPLUS: Percent = AlternativeFeeSurplus::get(); } diff --git a/runtime/karura/src/lib.rs b/runtime/karura/src/lib.rs index 4766805fad..83322fef88 100644 --- a/runtime/karura/src/lib.rs +++ b/runtime/karura/src/lib.rs @@ -51,14 +51,14 @@ use sp_version::RuntimeVersion; use frame_support::pallet_prelude::InvalidTransaction; use frame_system::{EnsureRoot, RawOrigin}; -use module_asset_registry::{AssetIdMaps, EvmErc20InfoMapping, FixedRateOfAssetRegistry}; +use module_asset_registry::{AssetIdMaps, EvmErc20InfoMapping}; use module_cdp_engine::CollateralCurrencyIds; use module_currencies::BasicCurrencyAdapter; use module_evm::{runner::RunnerExtended, CallInfo, CreateInfo, EvmChainId, EvmTask}; use module_evm_accounts::EvmAddressMapping; use module_relaychain::RelayChainCallBuilder; use module_support::{AssetIdMapping, DispatchableTask, ExchangeRateProvider}; -use module_transaction_payment::{TargetedFeeAdjustment, TransactionFeePoolTrader}; +use module_transaction_payment::TargetedFeeAdjustment; use cumulus_pallet_parachain_system::RelaychainBlockNumberProvider; use orml_traits::{ @@ -97,12 +97,12 @@ pub use primitives::{ TradingPair, }; pub use runtime_common::{ - calculate_asset_ratio, cent, dollar, microcent, millicent, AcalaDropAssets, AllPrecompiles, - EnsureRootOrAllGeneralCouncil, EnsureRootOrAllTechnicalCommittee, EnsureRootOrHalfFinancialCouncil, - EnsureRootOrHalfGeneralCouncil, EnsureRootOrHalfHomaCouncil, EnsureRootOrOneGeneralCouncil, - EnsureRootOrOneThirdsTechnicalCommittee, EnsureRootOrThreeFourthsGeneralCouncil, - EnsureRootOrTwoThirdsGeneralCouncil, EnsureRootOrTwoThirdsTechnicalCommittee, ExchangeRate, - ExistentialDepositsTimesOneHundred, FinancialCouncilInstance, FinancialCouncilMembershipInstance, GasToWeight, + cent, dollar, microcent, millicent, AcalaDropAssets, AllPrecompiles, EnsureRootOrAllGeneralCouncil, + EnsureRootOrAllTechnicalCommittee, EnsureRootOrHalfFinancialCouncil, EnsureRootOrHalfGeneralCouncil, + EnsureRootOrHalfHomaCouncil, EnsureRootOrOneGeneralCouncil, EnsureRootOrOneThirdsTechnicalCommittee, + EnsureRootOrThreeFourthsGeneralCouncil, EnsureRootOrTwoThirdsGeneralCouncil, + EnsureRootOrTwoThirdsTechnicalCommittee, ExchangeRate, ExistentialDepositsTimesOneHundred, + FinancialCouncilInstance, FinancialCouncilMembershipInstance, FixedRateOfAsset, GasToWeight, GeneralCouncilInstance, GeneralCouncilMembershipInstance, HomaCouncilInstance, HomaCouncilMembershipInstance, MaxTipsOfPriority, OperationalFeeMultiplier, OperatorMembershipInstanceAcala, Price, ProxyType, Rate, Ratio, RuntimeBlockLength, RuntimeBlockWeights, SystemContractsFilter, TechnicalCommitteeInstance, @@ -2168,50 +2168,50 @@ impl Convert<(Call, SignedExtra), Result<(EthereumTransactionMessage, SignedExtr fn convert( (call, mut extra): (Call, SignedExtra), ) -> Result<(EthereumTransactionMessage, SignedExtra), InvalidTransaction> { - match call { - Call::EVM(module_evm::Call::eth_call { - action, - input, - value, - gas_limit, - storage_limit, - access_list, - valid_until, - }) => { - if System::block_number() > valid_until { - return Err(InvalidTransaction::Stale); - } - - let (_, _, _, _, mortality, check_nonce, _, charge, ..) = extra.clone(); + if let Call::EVM(module_evm::Call::eth_call { + action, + input, + value, + gas_limit, + storage_limit, + access_list, + valid_until, + }) = call + { + if System::block_number() > valid_until { + return Err(InvalidTransaction::Stale); + } - if mortality != frame_system::CheckEra::from(sp_runtime::generic::Era::Immortal) { - // require immortal - return Err(InvalidTransaction::BadProof); - } + let (_, _, _, _, mortality, check_nonce, _, charge, ..) = extra.clone(); - let nonce = check_nonce.nonce; - let tip = charge.0; - - extra.5.mark_as_ethereum_tx(valid_until); - - Ok(( - EthereumTransactionMessage { - chain_id: EVM::chain_id(), - genesis: System::block_hash(0), - nonce, - tip, - gas_limit, - storage_limit, - action, - value, - input, - valid_until, - access_list, - }, - extra, - )) + if mortality != frame_system::CheckEra::from(sp_runtime::generic::Era::Immortal) { + // require immortal + return Err(InvalidTransaction::BadProof); } - _ => Err(InvalidTransaction::BadProof), + + let nonce = check_nonce.nonce; + let tip = charge.0; + + extra.5.mark_as_ethereum_tx(valid_until); + + Ok(( + EthereumTransactionMessage { + chain_id: EVM::chain_id(), + genesis: System::block_hash(0), + nonce, + tip, + gas_limit, + storage_limit, + action, + value, + input, + valid_until, + access_list, + }, + extra, + )) + } else { + Err(InvalidTransaction::BadProof) } } } diff --git a/runtime/karura/src/xcm_config.rs b/runtime/karura/src/xcm_config.rs index 3583f7e64b..64f0146a4e 100644 --- a/runtime/karura/src/xcm_config.rs +++ b/runtime/karura/src/xcm_config.rs @@ -19,9 +19,8 @@ use super::{ constants::{fee::*, parachains}, AccountId, AssetIdMapping, AssetIdMaps, Balance, Call, Convert, Currencies, CurrencyId, Event, ExistentialDeposits, - FixedRateOfAssetRegistry, GetNativeCurrencyId, KaruraTreasuryAccount, NativeTokenExistentialDeposit, Origin, - ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, TransactionFeePoolTrader, UnknownTokens, XcmInterface, - XcmpQueue, KAR, KUSD, LKSM, + FixedRateOfAsset, GetNativeCurrencyId, KaruraTreasuryAccount, NativeTokenExistentialDeposit, Origin, ParachainInfo, + ParachainSystem, PolkadotXcm, Runtime, UnknownTokens, XcmInterface, XcmpQueue, KAR, KUSD, LKSM, }; use codec::{Decode, Encode}; pub use cumulus_primitives_core::ParaId; @@ -32,6 +31,7 @@ pub use frame_support::{ }; pub use module_asset_registry::{BuyWeightRateOfErc20, BuyWeightRateOfForeignAsset}; use module_support::HomaSubAccountXcm; +use module_transaction_payment::BuyWeightRateOfTransactionFeePool; use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key, MultiCurrency}; use orml_xcm_support::{DepositToAlternative, IsNativeConcrete, MultiCurrencyAdapter, MultiNativeAsset}; use pallet_xcm::XcmPassthrough; @@ -184,12 +184,11 @@ parameter_types! { (ksm_per_second() * 4) / 3 ); - pub ForeignAssetUnitsPerSecond: u128 = kar_per_second(); - pub KarPerSecondAsBased: u128 = kar_per_second(); + pub BaseRate: u128 = kar_per_second(); } pub type Trader = ( - TransactionFeePoolTrader, + FixedRateOfAsset>, FixedRateOfFungible, FixedRateOfFungible, FixedRateOfFungible, @@ -199,8 +198,8 @@ pub type Trader = ( FixedRateOfFungible, FixedRateOfFungible, FixedRateOfFungible, - FixedRateOfAssetRegistry>, - FixedRateOfAssetRegistry>, + FixedRateOfAsset>, + FixedRateOfAsset>, ); pub struct XcmConfig; diff --git a/runtime/mandala/src/lib.rs b/runtime/mandala/src/lib.rs index e04562d61f..6d328620c8 100644 --- a/runtime/mandala/src/lib.rs +++ b/runtime/mandala/src/lib.rs @@ -49,14 +49,14 @@ pub use frame_support::{ }; use frame_system::{EnsureRoot, RawOrigin}; use hex_literal::hex; -use module_asset_registry::{AssetIdMaps, EvmErc20InfoMapping, FixedRateOfAssetRegistry}; +use module_asset_registry::{AssetIdMaps, EvmErc20InfoMapping}; use module_cdp_engine::CollateralCurrencyIds; use module_currencies::{BasicCurrencyAdapter, Currency}; use module_evm::{runner::RunnerExtended, CallInfo, CreateInfo, EvmChainId, EvmTask}; use module_evm_accounts::EvmAddressMapping; use module_relaychain::RelayChainCallBuilder; use module_support::{AssetIdMapping, DispatchableTask, ExchangeRateProvider}; -use module_transaction_payment::{TargetedFeeAdjustment, TransactionFeePoolTrader}; +use module_transaction_payment::TargetedFeeAdjustment; use scale_info::TypeInfo; use orml_tokens::CurrencyAdapter; @@ -103,15 +103,15 @@ pub use primitives::{ TradingPair, }; pub use runtime_common::{ - calculate_asset_ratio, cent, dollar, microcent, millicent, AcalaDropAssets, AllPrecompiles, - EnsureRootOrAllGeneralCouncil, EnsureRootOrAllTechnicalCommittee, EnsureRootOrHalfFinancialCouncil, - EnsureRootOrHalfGeneralCouncil, EnsureRootOrHalfHomaCouncil, EnsureRootOrOneGeneralCouncil, - EnsureRootOrOneThirdsTechnicalCommittee, EnsureRootOrThreeFourthsGeneralCouncil, - EnsureRootOrTwoThirdsGeneralCouncil, EnsureRootOrTwoThirdsTechnicalCommittee, ExchangeRate, - ExistentialDepositsTimesOneHundred, FinancialCouncilInstance, FinancialCouncilMembershipInstance, GasToWeight, - GeneralCouncilInstance, GeneralCouncilMembershipInstance, HomaCouncilInstance, HomaCouncilMembershipInstance, - MaxTipsOfPriority, OffchainSolutionWeightLimit, OperationalFeeMultiplier, OperatorMembershipInstanceAcala, Price, - ProxyType, Rate, Ratio, RuntimeBlockLength, RuntimeBlockWeights, SystemContractsFilter, TechnicalCommitteeInstance, + cent, dollar, microcent, millicent, AcalaDropAssets, AllPrecompiles, EnsureRootOrAllGeneralCouncil, + EnsureRootOrAllTechnicalCommittee, EnsureRootOrHalfFinancialCouncil, EnsureRootOrHalfGeneralCouncil, + EnsureRootOrHalfHomaCouncil, EnsureRootOrOneGeneralCouncil, EnsureRootOrOneThirdsTechnicalCommittee, + EnsureRootOrThreeFourthsGeneralCouncil, EnsureRootOrTwoThirdsGeneralCouncil, + EnsureRootOrTwoThirdsTechnicalCommittee, ExchangeRate, ExistentialDepositsTimesOneHundred, + FinancialCouncilInstance, FinancialCouncilMembershipInstance, GasToWeight, GeneralCouncilInstance, + GeneralCouncilMembershipInstance, HomaCouncilInstance, HomaCouncilMembershipInstance, MaxTipsOfPriority, + OffchainSolutionWeightLimit, OperationalFeeMultiplier, OperatorMembershipInstanceAcala, Price, ProxyType, Rate, + Ratio, RuntimeBlockLength, RuntimeBlockWeights, SystemContractsFilter, TechnicalCommitteeInstance, TechnicalCommitteeMembershipInstance, TimeStampedPrice, TipPerWeightStep, ACA, AUSD, DOT, KSM, LDOT, RENBTC, }; pub use xcm::latest::prelude::*; diff --git a/runtime/mandala/src/xcm_config.rs b/runtime/mandala/src/xcm_config.rs index cc3358f1d5..e25a307ee5 100644 --- a/runtime/mandala/src/xcm_config.rs +++ b/runtime/mandala/src/xcm_config.rs @@ -18,9 +18,8 @@ use super::{ constants::fee::*, AccountId, AssetIdMapping, AssetIdMaps, Balance, Call, Convert, Currencies, CurrencyId, Event, - ExistentialDeposits, FixedRateOfAssetRegistry, GetNativeCurrencyId, NativeTokenExistentialDeposit, Origin, - ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, TransactionFeePoolTrader, TreasuryAccount, UnknownTokens, - XcmpQueue, ACA, + ExistentialDeposits, GetNativeCurrencyId, NativeTokenExistentialDeposit, Origin, ParachainInfo, ParachainSystem, + PolkadotXcm, Runtime, TreasuryAccount, UnknownTokens, XcmpQueue, ACA, }; use codec::{Decode, Encode}; pub use cumulus_primitives_core::ParaId; @@ -30,12 +29,13 @@ pub use frame_support::{ weights::Weight, }; use module_asset_registry::{BuyWeightRateOfErc20, BuyWeightRateOfForeignAsset}; +use module_transaction_payment::BuyWeightRateOfTransactionFeePool; use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key, MultiCurrency}; use orml_xcm_support::{DepositToAlternative, IsNativeConcrete, MultiCurrencyAdapter, MultiNativeAsset}; use pallet_xcm::XcmPassthrough; use polkadot_parachain::primitives::Sibling; use primitives::evm::is_system_contract; -use runtime_common::{AcalaDropAssets, EnsureRootOrHalfGeneralCouncil}; +use runtime_common::{native_currency_location, AcalaDropAssets, EnsureRootOrHalfGeneralCouncil, FixedRateOfAsset}; use xcm::latest::prelude::*; pub use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, @@ -125,16 +125,15 @@ parameter_types! { ).into(), aca_per_second() ); - pub ForeignAssetUnitsPerSecond: u128 = aca_per_second(); - pub AcaPerSecondAsBased: u128 = aca_per_second(); + pub BaseRate: u128 = aca_per_second(); } pub type Trader = ( - TransactionFeePoolTrader, + FixedRateOfAsset>, FixedRateOfFungible, FixedRateOfFungible, - FixedRateOfAssetRegistry>, - FixedRateOfAssetRegistry>, + FixedRateOfAsset>, + FixedRateOfAsset>, ); pub struct XcmConfig; @@ -227,11 +226,6 @@ pub type LocalAssetTransactor = MultiCurrencyAdapter< DepositToAlternative, >; -//TODO: use token registry currency type encoding -fn native_currency_location(id: CurrencyId) -> MultiLocation { - MultiLocation::new(1, X2(Parachain(ParachainInfo::get().into()), GeneralKey(id.encode()))) -} - pub struct CurrencyIdConvert; impl Convert> for CurrencyIdConvert { fn convert(id: CurrencyId) -> Option { @@ -239,8 +233,12 @@ impl Convert> for CurrencyIdConvert { use CurrencyId::{Erc20, ForeignAsset, Token}; match id { Token(DOT) => Some(MultiLocation::parent()), - Token(ACA) | Token(AUSD) | Token(LDOT) | Token(RENBTC) | Token(TAI) => Some(native_currency_location(id)), - Erc20(address) if !is_system_contract(address) => Some(native_currency_location(id)), + Token(ACA) | Token(AUSD) | Token(LDOT) | Token(RENBTC) | Token(TAI) => { + Some(native_currency_location(ParachainInfo::get().into(), id)) + } + Erc20(address) if !is_system_contract(address) => { + Some(native_currency_location(ParachainInfo::get().into(), id)) + } ForeignAsset(foreign_asset_id) => AssetIdMaps::::get_multi_location(foreign_asset_id), _ => None, }