mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-20 04:41:04 +00:00
XCM v1 (#2815)
* MultiAsset TWO * Draft next MultiAsset API. * XCM core builds * XCM Executor builds * XCM Builder builds * API changes making their way throughout * Some TODOs * Further build fixes * Basic compile builds * First test fixed * All executor tests fixed * Typo * Optimize subsume_assets and add test * Optimize checked_sub * XCM Builder first test fixed * Fix builder tests * Fix doc test * fix some doc tests * spelling * named fields for AllOf * Update xcm/src/v0/multiasset.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/src/v0/multiasset.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/src/v0/multiasset.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/src/v0/multiasset.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Reformat * Move to XCM version 1 * Spelling * warnings * Replace some more v0->v1s * warnings * format * Add max_assets param * building * test fixes * tests * another test * final test * tests * Rename Null -> Here * Introduce * More ergonomics * More ergonomics * test fix * test fixes * docs * BuyExecution includes * Fix XCM extrinsics * fmt * Make Vec<MultiAsset>/MultiAssets conversions safe * More MultiAssets conversion safety * spelling * fix doc test * Apply suggestions from code review Co-authored-by: Amar Singh <asinghchrony@protonmail.com> * Apply suggestions from code review Co-authored-by: Amar Singh <asinghchrony@protonmail.com> * fmt * Add v0, remove VersionedMultiAsset * Remove VersionedMultiLocation * Update xcm/src/v1/order.rs Co-authored-by: Amar Singh <asinghchrony@protonmail.com> * Update xcm/src/v1/mod.rs Co-authored-by: Amar Singh <asinghchrony@protonmail.com> * XCM v0 backwards compatibility * Full compatibility * fmt * Update xcm/pallet-xcm/src/lib.rs * Update xcm/src/v0/order.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Tweaks to versioning system * Fixes * fmt * Update xcm/xcm-executor/src/assets.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Update xcm/xcm-executor/src/assets.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Grumbles * Update xcm/src/v1/multiasset.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * fmt * Update xcm/src/v1/multiasset.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Update xcm/src/v1/multiasset.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Fixes * Formatting Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> Co-authored-by: Amar Singh <asinghchrony@protonmail.com> Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,7 @@ use frame_support::{
|
||||
dispatch::{Dispatchable, Parameter},
|
||||
weights::{GetDispatchInfo, PostDispatchInfo},
|
||||
};
|
||||
use xcm::v0::SendXcm;
|
||||
use xcm::latest::SendXcm;
|
||||
|
||||
/// The trait to parameterize the `XcmExecutor`.
|
||||
pub trait Config {
|
||||
|
||||
@@ -22,8 +22,8 @@ use frame_support::{
|
||||
weights::GetDispatchInfo,
|
||||
};
|
||||
use sp_std::{marker::PhantomData, prelude::*};
|
||||
use xcm::v0::{
|
||||
Error as XcmError, ExecuteXcm, MultiAsset, MultiLocation, Order, Outcome, Response, SendXcm,
|
||||
use xcm::latest::{
|
||||
Error as XcmError, ExecuteXcm, MultiAssets, MultiLocation, Order, Outcome, Response, SendXcm,
|
||||
Xcm,
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@ use traits::{
|
||||
};
|
||||
|
||||
mod assets;
|
||||
pub use assets::{AssetId, Assets};
|
||||
pub use assets::Assets;
|
||||
mod config;
|
||||
pub use config::Config;
|
||||
|
||||
@@ -94,10 +94,10 @@ impl<Config: config::Config> ExecuteXcm<Config::Call> for XcmExecutor<Config> {
|
||||
}
|
||||
|
||||
impl<Config: config::Config> XcmExecutor<Config> {
|
||||
fn reanchored(mut assets: Assets, dest: &MultiLocation) -> Vec<MultiAsset> {
|
||||
fn reanchored(mut assets: Assets, dest: &MultiLocation) -> MultiAssets {
|
||||
let inv_dest = Config::LocationInverter::invert_location(&dest);
|
||||
assets.prepend_location(&inv_dest);
|
||||
assets.into_assets_iter().collect::<Vec<_>>()
|
||||
assets.into_assets_iter().collect::<Vec<_>>().into()
|
||||
}
|
||||
|
||||
/// Execute the XCM and return the portion of weight of `shallow_weight + deep_weight` that `message` did not use.
|
||||
@@ -144,17 +144,15 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
(origin, Xcm::WithdrawAsset { assets, effects }) => {
|
||||
// Take `assets` from the origin account (on-chain) and place in holding.
|
||||
let mut holding = Assets::default();
|
||||
for asset in assets {
|
||||
ensure!(!asset.is_wildcard(), XcmError::Wildcard);
|
||||
for asset in assets.inner() {
|
||||
let withdrawn = Config::AssetTransactor::withdraw_asset(&asset, &origin)?;
|
||||
holding.saturating_subsume_all(withdrawn);
|
||||
holding.subsume_assets(withdrawn);
|
||||
}
|
||||
Some((holding, effects))
|
||||
},
|
||||
(origin, Xcm::ReserveAssetDeposit { assets, effects }) => {
|
||||
(origin, Xcm::ReserveAssetDeposited { assets, effects }) => {
|
||||
// check whether we trust origin to be our reserve location for this asset.
|
||||
for asset in assets.iter() {
|
||||
ensure!(!asset.is_wildcard(), XcmError::Wildcard);
|
||||
for asset in assets.inner() {
|
||||
// We only trust the origin to send us assets that they identify as their
|
||||
// sovereign assets.
|
||||
ensure!(
|
||||
@@ -162,31 +160,28 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
XcmError::UntrustedReserveLocation
|
||||
);
|
||||
}
|
||||
Some((Assets::from(assets), effects))
|
||||
Some((assets.into(), effects))
|
||||
},
|
||||
(origin, Xcm::TransferAsset { assets, dest }) => {
|
||||
(origin, Xcm::TransferAsset { assets, beneficiary }) => {
|
||||
// Take `assets` from the origin account (on-chain) and place into dest account.
|
||||
for asset in assets {
|
||||
ensure!(!asset.is_wildcard(), XcmError::Wildcard);
|
||||
Config::AssetTransactor::teleport_asset(&asset, &origin, &dest)?;
|
||||
for asset in assets.inner() {
|
||||
Config::AssetTransactor::beam_asset(&asset, &origin, &beneficiary)?;
|
||||
}
|
||||
None
|
||||
},
|
||||
(origin, Xcm::TransferReserveAsset { mut assets, dest, effects }) => {
|
||||
// Take `assets` from the origin account (on-chain) and place into dest account.
|
||||
let inv_dest = Config::LocationInverter::invert_location(&dest);
|
||||
for asset in assets.iter_mut() {
|
||||
ensure!(!asset.is_wildcard(), XcmError::Wildcard);
|
||||
Config::AssetTransactor::teleport_asset(&asset, &origin, &dest)?;
|
||||
asset.reanchor(&inv_dest)?;
|
||||
for asset in assets.inner() {
|
||||
Config::AssetTransactor::beam_asset(asset, &origin, &dest)?;
|
||||
}
|
||||
Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposit { assets, effects })?;
|
||||
assets.reanchor(&inv_dest)?;
|
||||
Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposited { assets, effects })?;
|
||||
None
|
||||
},
|
||||
(origin, Xcm::TeleportAsset { assets, effects }) => {
|
||||
(origin, Xcm::ReceiveTeleportedAsset { assets, effects }) => {
|
||||
// check whether we trust origin to teleport this asset to us via config trait.
|
||||
for asset in assets.iter() {
|
||||
ensure!(!asset.is_wildcard(), XcmError::Wildcard);
|
||||
for asset in assets.inner() {
|
||||
// We only trust the origin to send us assets that they identify as their
|
||||
// sovereign assets.
|
||||
ensure!(
|
||||
@@ -198,7 +193,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
// don't want to punish a possibly innocent chain/user).
|
||||
Config::AssetTransactor::can_check_in(&origin, asset)?;
|
||||
}
|
||||
for asset in assets.iter() {
|
||||
for asset in assets.inner() {
|
||||
Config::AssetTransactor::check_in(&origin, asset);
|
||||
}
|
||||
Some((Assets::from(assets), effects))
|
||||
@@ -252,41 +247,41 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
|
||||
if let Some((mut holding, effects)) = maybe_holding_effects {
|
||||
for effect in effects.into_iter() {
|
||||
total_surplus += Self::execute_effects(&origin, &mut holding, effect, trader)?;
|
||||
total_surplus += Self::execute_orders(&origin, &mut holding, effect, trader)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(total_surplus)
|
||||
}
|
||||
|
||||
fn execute_effects(
|
||||
fn execute_orders(
|
||||
origin: &MultiLocation,
|
||||
holding: &mut Assets,
|
||||
effect: Order<Config::Call>,
|
||||
order: Order<Config::Call>,
|
||||
trader: &mut Config::Trader,
|
||||
) -> Result<Weight, XcmError> {
|
||||
log::trace!(
|
||||
target: "xcm::execute_effects",
|
||||
target: "xcm::execute_orders",
|
||||
"origin: {:?}, holding: {:?}, effect: {:?}",
|
||||
origin,
|
||||
holding,
|
||||
effect,
|
||||
order,
|
||||
);
|
||||
let mut total_surplus = 0;
|
||||
match effect {
|
||||
Order::DepositAsset { assets, dest } => {
|
||||
let deposited = holding.saturating_take(assets);
|
||||
match order {
|
||||
Order::DepositAsset { assets, max_assets, beneficiary } => {
|
||||
let deposited = holding.limited_saturating_take(assets, max_assets as usize);
|
||||
for asset in deposited.into_assets_iter() {
|
||||
Config::AssetTransactor::deposit_asset(&asset, &dest)?;
|
||||
Config::AssetTransactor::deposit_asset(&asset, &beneficiary)?;
|
||||
}
|
||||
},
|
||||
Order::DepositReserveAsset { assets, dest, effects } => {
|
||||
let deposited = holding.saturating_take(assets);
|
||||
Order::DepositReserveAsset { assets, max_assets, dest, effects } => {
|
||||
let deposited = holding.limited_saturating_take(assets, max_assets as usize);
|
||||
for asset in deposited.assets_iter() {
|
||||
Config::AssetTransactor::deposit_asset(&asset, &dest)?;
|
||||
}
|
||||
let assets = Self::reanchored(deposited, &dest);
|
||||
Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposit { assets, effects })?;
|
||||
Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposited { assets, effects })?;
|
||||
},
|
||||
Order::InitiateReserveWithdraw { assets, reserve, effects } => {
|
||||
let assets = Self::reanchored(holding.saturating_take(assets), &reserve);
|
||||
@@ -299,29 +294,37 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
Config::AssetTransactor::check_out(&origin, &asset);
|
||||
}
|
||||
let assets = Self::reanchored(assets, &dest);
|
||||
Config::XcmSender::send_xcm(dest, Xcm::TeleportAsset { assets, effects })?;
|
||||
Config::XcmSender::send_xcm(dest, Xcm::ReceiveTeleportedAsset { assets, effects })?;
|
||||
},
|
||||
Order::QueryHolding { query_id, dest, assets } => {
|
||||
let assets = Self::reanchored(holding.min(assets.iter()), &dest);
|
||||
let assets = Self::reanchored(holding.min(&assets), &dest);
|
||||
Config::XcmSender::send_xcm(
|
||||
dest,
|
||||
Xcm::QueryResponse { query_id, response: Response::Assets(assets) },
|
||||
)?;
|
||||
},
|
||||
Order::BuyExecution { fees, weight, debt, halt_on_error, xcm } => {
|
||||
// pay for `weight` using up to `fees` of the holding account.
|
||||
Order::BuyExecution { fees, weight, debt, halt_on_error, orders, instructions } => {
|
||||
// pay for `weight` using up to `fees` of the holding register.
|
||||
let purchasing_weight =
|
||||
Weight::from(weight.checked_add(debt).ok_or(XcmError::Overflow)?);
|
||||
let max_fee = holding.try_take(fees).map_err(|()| XcmError::NotHoldingFees)?;
|
||||
let max_fee =
|
||||
holding.try_take(fees.into()).map_err(|_| XcmError::NotHoldingFees)?;
|
||||
let unspent = trader.buy_weight(purchasing_weight, max_fee)?;
|
||||
holding.saturating_subsume_all(unspent);
|
||||
holding.subsume_assets(unspent);
|
||||
|
||||
let mut remaining_weight = weight;
|
||||
for message in xcm.into_iter() {
|
||||
for order in orders.into_iter() {
|
||||
match Self::execute_orders(origin, holding, order, trader) {
|
||||
Err(e) if halt_on_error => return Err(e),
|
||||
Err(_) => {},
|
||||
Ok(surplus) => total_surplus += surplus,
|
||||
}
|
||||
}
|
||||
for instruction in instructions.into_iter() {
|
||||
match Self::do_execute_xcm(
|
||||
origin.clone(),
|
||||
false,
|
||||
message,
|
||||
instruction,
|
||||
&mut remaining_weight,
|
||||
None,
|
||||
trader,
|
||||
@@ -331,7 +334,9 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
Ok(surplus) => total_surplus += surplus,
|
||||
}
|
||||
}
|
||||
holding.saturating_subsume(trader.refund_weight(remaining_weight));
|
||||
if let Some(w) = trader.refund_weight(remaining_weight) {
|
||||
holding.subsume(w);
|
||||
}
|
||||
},
|
||||
_ => return Err(XcmError::UnhandledEffect)?,
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use sp_std::{borrow::Borrow, convert::TryFrom, prelude::*, result::Result};
|
||||
use xcm::v0::{MultiLocation, OriginKind};
|
||||
use xcm::latest::{MultiLocation, OriginKind};
|
||||
|
||||
/// Generic third-party conversion trait. Use this when you don't want to force the user to use default
|
||||
/// implementations of `From` and `Into` for the types you wish to convert between.
|
||||
@@ -139,7 +139,7 @@ impl<T: Clone + Encode + Decode> Convert<Vec<u8>, T> for Decoded {
|
||||
/// which is passed to the next convert item.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use xcm::v0::{MultiLocation, Junction, OriginKind};
|
||||
/// # use xcm::latest::{MultiLocation, Junction, OriginKind};
|
||||
/// # use xcm_executor::traits::ConvertOrigin;
|
||||
/// // A convertor that will bump the para id and pass it to the next one.
|
||||
/// struct BumpParaId;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use xcm::v0::{MultiAsset, MultiLocation};
|
||||
use xcm::latest::{MultiAsset, MultiLocation};
|
||||
|
||||
/// Filters assets/location pairs.
|
||||
///
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use xcm::v0::MultiAsset;
|
||||
use xcm::latest::MultiAsset;
|
||||
|
||||
pub trait MatchesFungible<Balance> {
|
||||
fn matches_fungible(a: &MultiAsset) -> Option<Balance>;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use sp_std::result;
|
||||
use xcm::v0::{Error as XcmError, MultiAsset};
|
||||
use xcm::latest::{Error as XcmError, MultiAsset};
|
||||
|
||||
/// Errors associated with [`MatchesFungibles`] operation.
|
||||
pub enum Error {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use frame_support::weights::Weight;
|
||||
use xcm::v0::{MultiLocation, Response};
|
||||
use xcm::latest::{MultiLocation, Response};
|
||||
|
||||
/// Define what needs to be done upon receiving a query response.
|
||||
pub trait OnResponse {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
use frame_support::weights::Weight;
|
||||
use sp_std::result::Result;
|
||||
use xcm::v0::{MultiLocation, Xcm};
|
||||
use xcm::latest::{MultiLocation, Xcm};
|
||||
|
||||
/// Trait to determine whether the execution engine should actually execute a given XCM.
|
||||
///
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
use crate::Assets;
|
||||
use sp_std::result::Result;
|
||||
use xcm::v0::{Error as XcmError, MultiAsset, MultiLocation, Result as XcmResult};
|
||||
use xcm::latest::{Error as XcmError, MultiAsset, MultiLocation, Result as XcmResult};
|
||||
|
||||
/// Facility for asset transacting.
|
||||
///
|
||||
@@ -89,7 +89,7 @@ pub trait TransactAsset {
|
||||
/// Move an `asset` `from` one location in `to` another location.
|
||||
///
|
||||
/// Attempts to use `transfer_asset` and if not available then falls back to using a two-part withdraw/deposit.
|
||||
fn teleport_asset(
|
||||
fn beam_asset(
|
||||
asset: &MultiAsset,
|
||||
from: &MultiLocation,
|
||||
to: &MultiLocation,
|
||||
@@ -111,7 +111,7 @@ impl TransactAsset for Tuple {
|
||||
fn can_check_in(origin: &MultiLocation, what: &MultiAsset) -> XcmResult {
|
||||
for_tuples!( #(
|
||||
match Tuple::can_check_in(origin, what) {
|
||||
Err(XcmError::AssetNotFound | XcmError::Unimplemented) => (),
|
||||
Err(XcmError::AssetNotFound) | Err(XcmError::Unimplemented) => (),
|
||||
r => return r,
|
||||
}
|
||||
)* );
|
||||
@@ -139,7 +139,7 @@ impl TransactAsset for Tuple {
|
||||
fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> XcmResult {
|
||||
for_tuples!( #(
|
||||
match Tuple::deposit_asset(what, who) {
|
||||
Err(XcmError::AssetNotFound | XcmError::Unimplemented) => (),
|
||||
Err(XcmError::AssetNotFound) | Err(XcmError::Unimplemented) => (),
|
||||
r => return r,
|
||||
}
|
||||
)* );
|
||||
@@ -155,7 +155,7 @@ impl TransactAsset for Tuple {
|
||||
fn withdraw_asset(what: &MultiAsset, who: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
for_tuples!( #(
|
||||
match Tuple::withdraw_asset(what, who) {
|
||||
Err(XcmError::AssetNotFound | XcmError::Unimplemented) => (),
|
||||
Err(XcmError::AssetNotFound) | Err(XcmError::Unimplemented) => (),
|
||||
r => return r,
|
||||
}
|
||||
)* );
|
||||
@@ -175,7 +175,7 @@ impl TransactAsset for Tuple {
|
||||
) -> Result<Assets, XcmError> {
|
||||
for_tuples!( #(
|
||||
match Tuple::transfer_asset(what, from, to) {
|
||||
Err(XcmError::AssetNotFound | XcmError::Unimplemented) => (),
|
||||
Err(XcmError::AssetNotFound) | Err(XcmError::Unimplemented) => (),
|
||||
r => return r,
|
||||
}
|
||||
)* );
|
||||
@@ -193,6 +193,7 @@ impl TransactAsset for Tuple {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use MultiLocation::Here;
|
||||
|
||||
pub struct UnimplementedTransactor;
|
||||
impl TransactAsset for UnimplementedTransactor {}
|
||||
@@ -272,7 +273,7 @@ mod tests {
|
||||
(UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor);
|
||||
|
||||
assert_eq!(
|
||||
MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null),
|
||||
MultiTransactor::deposit_asset(&(Here, 1).into(), &Here),
|
||||
Err(XcmError::AssetNotFound)
|
||||
);
|
||||
}
|
||||
@@ -281,7 +282,7 @@ mod tests {
|
||||
fn unimplemented_and_not_found_continue_iteration() {
|
||||
type MultiTransactor = (UnimplementedTransactor, NotFoundTransactor, SuccessfulTransactor);
|
||||
|
||||
assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Ok(()));
|
||||
assert_eq!(MultiTransactor::deposit_asset(&(Here, 1).into(), &Here), Ok(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -289,7 +290,7 @@ mod tests {
|
||||
type MultiTransactor = (OverflowTransactor, SuccessfulTransactor);
|
||||
|
||||
assert_eq!(
|
||||
MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null),
|
||||
MultiTransactor::deposit_asset(&(Here, 1).into(), &Here),
|
||||
Err(XcmError::Overflow)
|
||||
);
|
||||
}
|
||||
@@ -298,6 +299,6 @@ mod tests {
|
||||
fn success_stops_iteration() {
|
||||
type MultiTransactor = (SuccessfulTransactor, OverflowTransactor);
|
||||
|
||||
assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Ok(()));
|
||||
assert_eq!(MultiTransactor::deposit_asset(&(Here, 1).into(), &Here), Ok(()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use crate::Assets;
|
||||
use frame_support::weights::Weight;
|
||||
use sp_std::result::Result;
|
||||
use xcm::v0::{Error, MultiAsset, MultiLocation, Xcm};
|
||||
use xcm::latest::{Error, MultiAsset, MultiLocation, Xcm};
|
||||
|
||||
/// Determine the weight of an XCM message.
|
||||
pub trait WeightBounds<Call> {
|
||||
@@ -71,8 +71,8 @@ pub trait WeightTrader: Sized {
|
||||
/// purchased using `buy_weight`.
|
||||
///
|
||||
/// Default implementation refunds nothing.
|
||||
fn refund_weight(&mut self, _weight: Weight) -> MultiAsset {
|
||||
MultiAsset::None
|
||||
fn refund_weight(&mut self, _weight: Weight) -> Option<MultiAsset> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user