Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
refactor weight trader
  • Loading branch information
zqhxuyuan committed Jun 2, 2022
commit 39bec0d1966376468b11d61c04a2ccce2de6cf38
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

118 changes: 0 additions & 118 deletions modules/asset-registry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ 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};
Expand All @@ -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;
Expand Down Expand Up @@ -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<FixedRate: Get<u128>, R: TakeRevenue, M: BuyWeightRate> {
weight: Weight,
amount: u128,
ed_ratio: FixedU128,
multi_location: Option<MultiLocation>,
_marker: PhantomData<(FixedRate, R, M)>,
}

impl<FixedRate: Get<u128>, R: TakeRevenue, M: BuyWeightRate> WeightTrader
for FixedRateOfAssetRegistry<FixedRate, R, M>
{
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<Assets, XcmError> {
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<MultiAsset> {
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<FixedRate: Get<u128>, R: TakeRevenue, M: BuyWeightRate> Drop for FixedRateOfAssetRegistry<FixedRate, R, M> {
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<T>(sp_std::marker::PhantomData<T>);

impl<T: Config> EvmErc20InfoMapping<T> {
Expand Down
94 changes: 8 additions & 86 deletions modules/transaction-payment/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand All @@ -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, Rate, Ratio, SwapLimit, TransactionPayment};
use xcm::opaque::latest::MultiLocation;

mod mock;
mod tests;
Expand Down Expand Up @@ -1074,94 +1069,21 @@ 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<T, C, K: Get<u128>, R: TakeRevenue> {
weight: Weight,
amount: u128,
asset_location: Option<MultiLocation>,
asset_per_second: u128,
_marker: PhantomData<(T, C, K, R)>,
}
pub struct BuyWeightRateOfTransactionFeePool<T, C>(sp_std::marker::PhantomData<(T, C)>);

impl<T: Config, C, K: Get<u128>, R: TakeRevenue> WeightTrader for TransactionFeePoolTrader<T, C, K, R>
impl<T: Config, C> BuyWeightRate for BuyWeightRateOfTransactionFeePool<T, C>
where
C: Convert<MultiLocation, Option<CurrencyId>>,
{
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<Assets, XcmError> {
// 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::<T>::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<MultiAsset> {
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(),
)
fn calculate_rate(multi_location: MultiLocation) -> Option<Rate> {
if let Some(token_id) = C::convert(multi_location) {
TokenExchangeRate::<T>::get(token_id)
} else {
None
}
}
}

impl<T, C, K: Get<u128>, R: TakeRevenue> Drop for TransactionFeePoolTrader<T, C, K, R> {
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<T> Convert<Weight, PalletBalanceOf<T>> for Pallet<T>
where
T: Config,
Expand Down
33 changes: 0 additions & 33 deletions modules/transaction-payment/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1362,39 +1362,6 @@ impl Convert<MultiLocation, Option<CurrencyId>> for CurrencyIdConvert {
}
}

#[test]
fn period_rate_buy_refund_weight_works() {
parameter_types! {
pub const NativePerSecond: u128 = 8_000_000_000_000;
}
builder_with_dex_and_fee_pool(true).execute_with(|| {
let mock_weight: Weight = 200_000_000;
let dot_rate = TokenExchangeRate::<Runtime>::get(DOT);
let usd_rate = TokenExchangeRate::<Runtime>::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::<Runtime, CurrencyIdConvert, NativePerSecond, ()>::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::<Runtime, CurrencyIdConvert, NativePerSecond, ()>::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);
});
}

#[test]
fn swap_from_pool_not_enough_currency() {
builder_with_dex_and_fee_pool(true).execute_with(|| {
Expand Down
4 changes: 2 additions & 2 deletions runtime/acala/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down
21 changes: 12 additions & 9 deletions runtime/acala/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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::{AcalaDropAssets, EnsureRootOrHalfGeneralCouncil, FixedRateOfAssetRegistry};
use xcm::latest::prelude::*;
pub use xcm_builder::{
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
Expand Down Expand Up @@ -133,17 +133,20 @@ parameter_types! {
).into(),
aca_per_second()
);
pub ForeignAssetUnitsPerSecond: u128 = aca_per_second();
pub AcaPerSecondAsBased: u128 = aca_per_second();
pub NativeTokenPerSecond: u128 = aca_per_second();
}

pub type Trader = (
TransactionFeePoolTrader<Runtime, CurrencyIdConvert, AcaPerSecondAsBased, ToTreasury>,
FixedRateOfAssetRegistry<
NativeTokenPerSecond,
ToTreasury,
BuyWeightRateOfTransactionFeePool<Runtime, CurrencyIdConvert>,
>,
FixedRateOfFungible<DotPerSecond, ToTreasury>,
FixedRateOfFungible<AusdPerSecond, ToTreasury>,
FixedRateOfFungible<AcaPerSecond, ToTreasury>,
FixedRateOfAssetRegistry<ForeignAssetUnitsPerSecond, ToTreasury, BuyWeightRateOfForeignAsset<Runtime>>,
FixedRateOfAssetRegistry<ForeignAssetUnitsPerSecond, ToTreasury, BuyWeightRateOfErc20<Runtime>>,
FixedRateOfAssetRegistry<NativeTokenPerSecond, ToTreasury, BuyWeightRateOfForeignAsset<Runtime>>,
FixedRateOfAssetRegistry<NativeTokenPerSecond, ToTreasury, BuyWeightRateOfErc20<Runtime>>,
);

pub struct XcmConfig;
Expand Down
Loading