mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 07:01:03 +00:00
Add XCM Origin and converter (#2896)
* Add XCM Origin and converter * IsMajority filter can be location-prefixed * Update xcm/pallet-xcm/src/lib.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/src/v0/multi_location.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Introduce UsingComponents to allow reuse of fee payment in XCM * Use Drop rather than finalize * Add errors for weight. * Apply suggestions from code review Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Fixes * Update xcm/xcm-builder/src/weight.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Various XCM fixes and improvements * Fixes * Update xcm/xcm-builder/src/weight.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/xcm-builder/src/weight.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/xcm-builder/src/weight.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Fixes Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
This commit is contained in:
@@ -16,6 +16,7 @@ sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", de
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
|
||||
# Polkadot dependencies
|
||||
polkadot-parachain = { path = "../../parachain", default-features = false }
|
||||
@@ -33,4 +34,5 @@ std = [
|
||||
"sp-runtime/std",
|
||||
"frame-support/std",
|
||||
"polkadot-parachain/std",
|
||||
"pallet-transaction-payment/std",
|
||||
]
|
||||
|
||||
@@ -46,7 +46,7 @@ mod fungibles_adapter;
|
||||
pub use fungibles_adapter::FungiblesAdapter;
|
||||
|
||||
mod weight;
|
||||
pub use weight::{FixedRateOfConcreteFungible, FixedWeightBounds};
|
||||
pub use weight::{FixedRateOfConcreteFungible, FixedWeightBounds, UsingComponents};
|
||||
|
||||
mod matches_fungible;
|
||||
pub use matches_fungible::{IsAbstract, IsConcrete};
|
||||
|
||||
@@ -272,6 +272,6 @@ impl Config for TestConfig {
|
||||
type LocationInverter = LocationInverter<TestAncestry>;
|
||||
type Barrier = TestBarrier;
|
||||
type Weigher = FixedWeightBounds<UnitWeightCost, TestCall>;
|
||||
type Trader = FixedRateOfConcreteFungible<WeightPrice>;
|
||||
type Trader = FixedRateOfConcreteFungible<WeightPrice, ()>;
|
||||
type ResponseHandler = TestResponseHandler;
|
||||
}
|
||||
|
||||
@@ -14,19 +14,22 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use sp_std::{result::Result, marker::PhantomData};
|
||||
use sp_std::{result::Result, marker::PhantomData, convert::TryInto};
|
||||
use parity_scale_codec::Decode;
|
||||
use xcm::v0::{Xcm, Order, MultiAsset, MultiLocation};
|
||||
use frame_support::{traits::Get, weights::{Weight, GetDispatchInfo}};
|
||||
use xcm::v0::{Xcm, Order, MultiAsset, MultiLocation, Error};
|
||||
use sp_runtime::traits::{Zero, Saturating, SaturatedConversion};
|
||||
use frame_support::traits::{Get, OnUnbalanced as OnUnbalancedT, tokens::currency::Currency as CurrencyT};
|
||||
use frame_support::weights::{Weight, GetDispatchInfo, WeightToFeePolynomial};
|
||||
use xcm_executor::{Assets, traits::{WeightBounds, WeightTrader}};
|
||||
|
||||
pub struct FixedWeightBounds<T, C>(PhantomData<(T, C)>);
|
||||
impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeightBounds<T, C> {
|
||||
fn shallow(message: &mut Xcm<C>) -> Result<Weight, ()> {
|
||||
let min = match message {
|
||||
Ok(match message {
|
||||
Xcm::Transact { call, .. } => {
|
||||
call.ensure_decoded()?.get_dispatch_info().weight + T::get()
|
||||
}
|
||||
Xcm::RelayedFrom { ref mut message, .. } => T::get() + Self::shallow(message.as_mut())?,
|
||||
Xcm::WithdrawAsset { effects, .. }
|
||||
| Xcm::ReserveAssetDeposit { effects, .. }
|
||||
| Xcm::TeleportAsset { effects, .. } => {
|
||||
@@ -45,16 +48,16 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeigh
|
||||
T::get() + inner
|
||||
}
|
||||
_ => T::get(),
|
||||
};
|
||||
Ok(min)
|
||||
})
|
||||
}
|
||||
fn deep(message: &mut Xcm<C>) -> Result<Weight, ()> {
|
||||
let mut extra = 0;
|
||||
match message {
|
||||
Xcm::Transact { .. } => {}
|
||||
Ok(match message {
|
||||
Xcm::RelayedFrom { ref mut message, .. } => Self::deep(message.as_mut())?,
|
||||
Xcm::WithdrawAsset { effects, .. }
|
||||
| Xcm::ReserveAssetDeposit { effects, .. }
|
||||
| Xcm::TeleportAsset { effects, .. } => {
|
||||
| Xcm::TeleportAsset { effects, .. }
|
||||
=> {
|
||||
let mut extra = 0;
|
||||
for effect in effects.iter_mut() {
|
||||
match effect {
|
||||
Order::BuyExecution { xcm, .. } => {
|
||||
@@ -65,34 +68,116 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeigh
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
Ok(extra)
|
||||
extra
|
||||
},
|
||||
_ => 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Function trait for handling some revenue. Similar to a negative imbalance (credit) handler, but for a
|
||||
/// `MultiAsset`. Sensible implementations will deposit the asset in some known treasury or block-author account.
|
||||
pub trait TakeRevenue {
|
||||
/// Do something with the given `revenue`, which is a single non-wildcard `MultiAsset`.
|
||||
fn take_revenue(revenue: MultiAsset);
|
||||
}
|
||||
|
||||
/// Null implementation just burns the revenue.
|
||||
impl TakeRevenue for () {
|
||||
fn take_revenue(_revenue: MultiAsset) {}
|
||||
}
|
||||
|
||||
/// Simple fee calculator that requires payment in a single concrete fungible at a fixed rate.
|
||||
///
|
||||
/// The constant `Get` type parameter should be the concrete fungible ID and the amount of it required for
|
||||
/// one second of weight.
|
||||
pub struct FixedRateOfConcreteFungible<T>(Weight, PhantomData<T>);
|
||||
impl<T: Get<(MultiLocation, u128)>> WeightTrader for FixedRateOfConcreteFungible<T> {
|
||||
fn new() -> Self { Self(0, PhantomData) }
|
||||
fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, ()> {
|
||||
pub struct FixedRateOfConcreteFungible<
|
||||
T: Get<(MultiLocation, u128)>,
|
||||
R: TakeRevenue,
|
||||
>(Weight, u128, PhantomData<(T, R)>);
|
||||
impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> WeightTrader for FixedRateOfConcreteFungible<T, R> {
|
||||
fn new() -> Self { Self(0, 0, PhantomData) }
|
||||
|
||||
fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, Error> {
|
||||
let (id, units_per_second) = T::get();
|
||||
let amount = units_per_second * (weight as u128) / 1_000_000_000_000u128;
|
||||
use frame_support::weights::constants::WEIGHT_PER_SECOND;
|
||||
let amount = units_per_second * (weight as u128) / (WEIGHT_PER_SECOND as u128);
|
||||
let required = MultiAsset::ConcreteFungible { amount, id };
|
||||
let (used, _) = payment.less(required).map_err(|_| ())?;
|
||||
let (unused, _) = payment.less(required).map_err(|_| Error::TooExpensive)?;
|
||||
self.0 = self.0.saturating_add(weight);
|
||||
Ok(used)
|
||||
self.1 = self.1.saturating_add(amount);
|
||||
Ok(unused)
|
||||
}
|
||||
|
||||
fn refund_weight(&mut self, weight: Weight) -> MultiAsset {
|
||||
let weight = weight.min(self.0);
|
||||
self.0 -= weight;
|
||||
let (id, units_per_second) = T::get();
|
||||
let weight = weight.min(self.0);
|
||||
let amount = units_per_second * (weight as u128) / 1_000_000_000_000u128;
|
||||
self.0 -= weight;
|
||||
self.1 = self.1.saturating_sub(amount);
|
||||
let result = MultiAsset::ConcreteFungible { amount, id };
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> Drop for FixedRateOfConcreteFungible<T, R> {
|
||||
fn drop(&mut self) {
|
||||
let revenue = MultiAsset::ConcreteFungible { amount: self.1, id: T::get().0 };
|
||||
R::take_revenue(revenue);
|
||||
}
|
||||
}
|
||||
|
||||
/// Weight trader which uses the TransactionPayment pallet to set the right price for weight and then
|
||||
/// places any weight bought into the right account.
|
||||
pub struct UsingComponents<
|
||||
WeightToFee: WeightToFeePolynomial<Balance=Currency::Balance>,
|
||||
AssetId: Get<MultiLocation>,
|
||||
AccountId,
|
||||
Currency: CurrencyT<AccountId>,
|
||||
OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
|
||||
>(Weight, Currency::Balance, PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>);
|
||||
impl<
|
||||
WeightToFee: WeightToFeePolynomial<Balance=Currency::Balance>,
|
||||
AssetId: Get<MultiLocation>,
|
||||
AccountId,
|
||||
Currency: CurrencyT<AccountId>,
|
||||
OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
|
||||
> WeightTrader for UsingComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> {
|
||||
fn new() -> Self { Self(0, Zero::zero(), PhantomData) }
|
||||
|
||||
fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, Error> {
|
||||
let amount = WeightToFee::calc(&weight);
|
||||
let required = MultiAsset::ConcreteFungible {
|
||||
amount: amount.try_into().map_err(|_| Error::Overflow)?,
|
||||
id: AssetId::get(),
|
||||
};
|
||||
let (unused, _) = payment.less(required).map_err(|_| Error::TooExpensive)?;
|
||||
self.0 = self.0.saturating_add(weight);
|
||||
self.1 = self.1.saturating_add(amount);
|
||||
Ok(unused)
|
||||
}
|
||||
|
||||
fn refund_weight(&mut self, weight: Weight) -> MultiAsset {
|
||||
let weight = weight.min(self.0);
|
||||
let amount = WeightToFee::calc(&weight);
|
||||
self.0 -= weight;
|
||||
self.1 = self.1.saturating_sub(amount);
|
||||
let result = MultiAsset::ConcreteFungible {
|
||||
amount: amount.saturated_into(),
|
||||
id: AssetId::get(),
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
}
|
||||
impl<
|
||||
WeightToFee: WeightToFeePolynomial<Balance=Currency::Balance>,
|
||||
AssetId: Get<MultiLocation>,
|
||||
AccountId,
|
||||
Currency: CurrencyT<AccountId>,
|
||||
OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
|
||||
> Drop for UsingComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> {
|
||||
fn drop(&mut self) {
|
||||
OnUnbalanced::on_unbalanced(Currency::issue(self.1));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user