Skip to content

Commit

Permalink
Add XcmWeightTrader, XcmPaymentApi and DryRunApi #1484 (#1490)
Browse files Browse the repository at this point in the history
* Add XcmWeightTrader, XcmPaymentApi and DryRunApi #1484

* Update lib.rs
  • Loading branch information
hqwangningbo authored Nov 5, 2024
1 parent b0a58c0 commit b60ba06
Show file tree
Hide file tree
Showing 19 changed files with 343 additions and 395 deletions.
18 changes: 10 additions & 8 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ substrate-fixed = { git = "https://github.com/encoint
xcm = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.13.0", package = "staging-xcm", default-features = false }
xcm-builder = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.13.0", package = "staging-xcm-builder", default-features = false }
xcm-executor = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.13.0", package = "staging-xcm-executor", default-features = false }
xcm-fee-payment-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.13.0", default-features = false }

# polkadot-sdk (client)
cumulus-client-cli = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.13.0" }
Expand Down
155 changes: 13 additions & 142 deletions pallets/asset-registry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,19 @@ use frame_support::{
ensure,
pallet_prelude::*,
traits::{Currency, EnsureOrigin},
weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight},
weights::Weight,
};
use frame_system::pallet_prelude::*;
use scale_info::{prelude::string::String, TypeInfo};
use sp_runtime::{
traits::{One, UniqueSaturatedFrom},
ArithmeticError, FixedPointNumber, FixedU128, RuntimeDebug,
ArithmeticError, RuntimeDebug,
};
use sp_std::{boxed::Box, vec::Vec};
use xcm::{
opaque::lts::XcmContext,
v3::MultiLocation,
v4::{prelude::*, Asset, Location},
v4::{prelude::*, Location},
VersionedLocation,
};
use xcm_builder::TakeRevenue;
use xcm_executor::{traits::WeightTrader, AssetsInHolding};

pub mod migrations;
mod mock;
Expand Down Expand Up @@ -423,13 +419,15 @@ impl<T: Config> Pallet<T> {

Ok(())
}

pub fn asset_ids() -> Vec<AssetId> {
LocationToCurrencyIds::<T>::iter_keys().map(|key| AssetId(key)).collect()
}
}

pub struct AssetIdMaps<T>(sp_std::marker::PhantomData<T>);
pub struct AssetIdMaps<T>(PhantomData<T>);

impl<T: Config> CurrencyIdMapping<CurrencyId, MultiLocation, AssetMetadata<BalanceOf<T>>>
for AssetIdMaps<T>
{
impl<T: Config> CurrencyIdMapping<CurrencyId, AssetMetadata<BalanceOf<T>>> for AssetIdMaps<T> {
fn get_asset_metadata(asset_ids: AssetIds) -> Option<AssetMetadata<BalanceOf<T>>> {
AssetMetadatas::<T>::get(asset_ids)
}
Expand All @@ -442,13 +440,12 @@ impl<T: Config> CurrencyIdMapping<CurrencyId, MultiLocation, AssetMetadata<Balan
CurrencyMetadatas::<T>::iter_keys().collect()
}

fn get_location(currency_id: CurrencyId) -> Option<Location> {
CurrencyIdToLocations::<T>::get(currency_id).map(|location| location.try_into().ok())?
fn get_location(currency_id: &CurrencyId) -> Option<Location> {
CurrencyIdToLocations::<T>::get(currency_id)
}

fn get_currency_id(multi_location: Location) -> Option<CurrencyId> {
let v4_location = Location::try_from(multi_location).ok()?;
LocationToCurrencyIds::<T>::get(v4_location)
fn get_currency_id(location: &Location) -> Option<CurrencyId> {
LocationToCurrencyIds::<T>::get(location)
}
}

Expand Down Expand Up @@ -586,129 +583,3 @@ impl<T: Config> CurrencyIdRegister<CurrencyId> for AssetIdMaps<T> {
)
}
}

/// 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 FixedRateOfAsset<T, FixedRate: Get<u128>, R: TakeRevenue> {
weight: u64,
amount: u128,
ed_ratio: FixedU128,
location: Option<Location>,
_marker: PhantomData<(T, FixedRate, R)>,
}

impl<T: Config, FixedRate: Get<u128>, R: TakeRevenue> WeightTrader
for FixedRateOfAsset<T, FixedRate, R>
where
BalanceOf<T>: Into<u128>,
{
fn new() -> Self {
Self {
weight: 0,
amount: 0,
ed_ratio: Default::default(),
location: None,
_marker: PhantomData,
}
}

fn buy_weight(
&mut self,
weight: Weight,
payment: AssetsInHolding,
_context: &XcmContext,
) -> Result<AssetsInHolding, 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))?;

let AssetId(ref location) = asset_id.clone();
log::debug!(target: "asset-registry::weight", "buy_weight location: {:?}", location);

let v4_location =
Location::try_from(location.clone()).map_err(|_| XcmError::InvalidLocation)?;

if let Some(currency_id) = LocationToCurrencyIds::<T>::get(v4_location) {
if let Some(currency_metadatas) = CurrencyMetadatas::<T>::get(currency_id) {
// The integration tests can ensure the ed is non-zero.
let ed_ratio = FixedU128::saturating_from_rational(
currency_metadatas.minimal_balance.into(),
T::Currency::minimum_balance().into(),
);
// The WEIGHT_REF_TIME_PER_SECOND is non-zero.
let weight_ratio = FixedU128::saturating_from_rational(
weight.ref_time(),
WEIGHT_REF_TIME_PER_SECOND,
);
let amount =
ed_ratio.saturating_mul_int(weight_ratio.saturating_mul_int(FixedRate::get()));

let required = Asset { 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.ref_time());
self.amount = self.amount.saturating_add(amount);
self.ed_ratio = ed_ratio;
self.location = Some(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, _context: &XcmContext) -> Option<Asset> {
log::trace!(
target: "asset-registry::weight", "refund_weight weight: {:?}, weight: {:?}, amount: {:?}, ed_ratio: {:?}, location: {:?}",
weight, self.weight, self.amount, self.ed_ratio, self.location
);
let weight = weight.min(Weight::from_parts(self.weight, 0));
let weight_ratio =
FixedU128::saturating_from_rational(weight.ref_time(), WEIGHT_REF_TIME_PER_SECOND);
let amount = self
.ed_ratio
.saturating_mul_int(weight_ratio.saturating_mul_int(FixedRate::get()));

self.weight = self.weight.saturating_sub(weight.ref_time());
self.amount = self.amount.saturating_sub(amount);

log::trace!(target: "asset-registry::weight", "refund_weight amount: {:?}", amount);
if amount > 0 && self.location.is_some() {
Some(Asset {
fun: Fungible(amount),
id: AssetId(
self.location.clone().expect("checked is non-empty; qed").try_into().unwrap(),
),
})
} else {
None
}
}
}

impl<T, FixedRate: Get<u128>, R: TakeRevenue> Drop for FixedRateOfAsset<T, FixedRate, R> {
fn drop(&mut self) {
log::trace!(target: "asset-registry::weight", "take revenue, weight: {:?}, amount: {:?}, location: {:?}", self.weight, self.amount, self.location);
if self.amount > 0 && self.location.is_some() {
R::take_revenue(Asset {
fun: Fungible(self.amount),
id: AssetId(
self.location.clone().expect("checked is non-empty; qed").try_into().unwrap(),
),
});
}
}
}
7 changes: 1 addition & 6 deletions pallets/prices/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ pub use pallet::*;
use pallet_traits::*;
use sp_runtime::{traits::CheckedDiv, FixedU128};
use sp_std::vec::Vec;
use xcm::v3::MultiLocation;

#[cfg(test)]
mod mock;
Expand Down Expand Up @@ -79,11 +78,7 @@ pub mod pallet {
type RelayCurrency: Get<CurrencyId>;

/// Convert Location to `T::CurrencyId`.
type CurrencyIdConvert: CurrencyIdMapping<
CurrencyId,
MultiLocation,
AssetMetadata<BalanceOf<Self>>,
>;
type CurrencyIdConvert: CurrencyIdMapping<CurrencyId, AssetMetadata<BalanceOf<Self>>>;

/// Weight information
type WeightInfo: WeightInfo;
Expand Down
6 changes: 1 addition & 5 deletions pallets/slp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,7 @@ pub mod pallet {
>;

// asset registry to get asset metadata
type AssetIdMaps: CurrencyIdMapping<
CurrencyId,
MultiLocation,
AssetMetadata<BalanceOf<Self>>,
>;
type AssetIdMaps: CurrencyIdMapping<CurrencyId, AssetMetadata<BalanceOf<Self>>>;

#[pallet::constant]
type TreasuryAccount: Get<Self::AccountId>;
Expand Down
6 changes: 1 addition & 5 deletions pallets/slpx/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,7 @@ pub mod pallet {
/// Send Xcm
type XcmSender: SendXcm;
/// Convert Location to `T::CurrencyId`.
type CurrencyIdConvert: CurrencyIdMapping<
CurrencyId,
xcm::v3::MultiLocation,
AssetMetadata<BalanceOf<Self>>,
>;
type CurrencyIdConvert: CurrencyIdMapping<CurrencyId, AssetMetadata<BalanceOf<Self>>>;
/// TreasuryAccount
#[pallet::constant]
type TreasuryAccount: Get<AccountIdOf<Self>>;
Expand Down
4 changes: 2 additions & 2 deletions pallets/slpx/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,13 +248,13 @@ parameter_types! {
pub struct CurrencyIdConvert<T>(sp_std::marker::PhantomData<T>);
impl<T: Get<ParaId>> Convert<CurrencyId, Option<Location>> for CurrencyIdConvert<T> {
fn convert(id: CurrencyId) -> Option<Location> {
AssetIdMaps::<Test>::get_location(id)
AssetIdMaps::<Test>::get_location(&id)
}
}

impl<T: Get<ParaId>> Convert<Location, Option<CurrencyId>> for CurrencyIdConvert<T> {
fn convert(location: Location) -> Option<CurrencyId> {
AssetIdMaps::<Test>::get_currency_id(location)
AssetIdMaps::<Test>::get_currency_id(&location)
}
}

Expand Down
10 changes: 3 additions & 7 deletions pallets/xcm-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,7 @@ pub mod pallet {
type AccountIdToLocation: Convert<Self::AccountId, Location>;

/// Convert Location to `T::CurrencyId`.
type CurrencyIdConvert: CurrencyIdMapping<
CurrencyId,
xcm::v3::MultiLocation,
AssetMetadata<BalanceOf<Self>>,
>;
type CurrencyIdConvert: CurrencyIdMapping<CurrencyId, AssetMetadata<BalanceOf<Self>>>;

#[pallet::constant]
type ParachainId: Get<ParaId>;
Expand Down Expand Up @@ -170,8 +166,8 @@ pub mod pallet {
to: H160,
) -> DispatchResult {
let who = ensure_signed(origin.clone())?;
let asset_location =
T::CurrencyIdConvert::get_location(currency_id).ok_or(Error::<T>::FailToConvert)?;
let asset_location = T::CurrencyIdConvert::get_location(&currency_id)
.ok_or(Error::<T>::FailToConvert)?;

let asset: Asset = Asset {
id: AssetId(asset_location),
Expand Down
7 changes: 4 additions & 3 deletions primitives/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use sp_runtime::{
BoundedVec, DispatchError, DispatchResult, TypeId,
};
use sp_std::{cmp::Ordering, fmt::Debug, vec::Vec};
use xcm::prelude::Location;

pub trait TokenInfo {
fn name(&self) -> Option<&str>;
Expand Down Expand Up @@ -143,15 +144,15 @@ pub trait SlpxOperator<Balance> {
}

/// A mapping between CurrencyId and AssetMetadata.
pub trait CurrencyIdMapping<CurrencyId, MultiLocation, AssetMetadata> {
pub trait CurrencyIdMapping<CurrencyId, AssetMetadata> {
/// Returns the AssetMetadata associated with a given `AssetIds`.
fn get_asset_metadata(asset_ids: AssetIds) -> Option<AssetMetadata>;
/// Returns the AssetMetadata associated with a given `CurrencyId`.
fn get_currency_metadata(currency_id: CurrencyId) -> Option<AssetMetadata>;
/// Returns the Location associated with a given CurrencyId.
fn get_location(currency_id: CurrencyId) -> Option<xcm::v4::Location>;
fn get_location(currency_id: &CurrencyId) -> Option<Location>;
/// Returns the CurrencyId associated with a given Location.
fn get_currency_id(multi_location: xcm::v4::Location) -> Option<CurrencyId>;
fn get_currency_id(location: &Location) -> Option<CurrencyId>;
/// Returns all currencies in currencyMetadata.
fn get_all_currency() -> Vec<CurrencyId>;
}
Expand Down
9 changes: 8 additions & 1 deletion primitives/src/xcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use sp_runtime::traits::Convert;
use sp_std::marker::PhantomData;
use xcm::{
latest::Asset,
prelude::{AccountId32, Ethereum, Fungible, GlobalConsensus, Parachain},
prelude::{AccountId32, Ethereum, Fungible, GeneralKey, GlobalConsensus, Parachain},
v4::{AssetId, InteriorLocation, Location, NetworkId, Parent},
};

Expand Down Expand Up @@ -58,6 +58,13 @@ parameter_types! {
pub SelfLocation: Location = Location::here();
pub AssetHubLocation: Location = Location::new(1, Parachain(AssetHubChainId::get()));
pub EthereumLocation: Location = Location::new(2, [GlobalConsensus(Ethereum { chain_id: EthereumChainId::get() })]);
pub LocalBncLocation: Location = Location::new(0, [GeneralKey {
length: 2,
data: [
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0
],
}]);

pub const KusamaNetwork: NetworkId = NetworkId::Kusama;
pub const PolkadotNetwork: NetworkId = NetworkId::Polkadot;
Expand Down
Loading

0 comments on commit b60ba06

Please sign in to comment.