Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
avoided AssetConversionAdapter, now using Swap trait
Browse files Browse the repository at this point in the history
  • Loading branch information
PatricioNapoli committed Jul 20, 2023
1 parent 1da4278 commit b3adbf6
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 105 deletions.
20 changes: 11 additions & 9 deletions parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ fn test_asset_xcm_trader() {
let mut trader = <XcmConfig as xcm_executor::Config>::Trader::new();

// Lets buy_weight and make sure buy_weight does not return an error
let unused_assets = trader.buy_weight(bought, asset.into()).expect("Expected Ok");
let unused_assets = trader.buy_weight(&XcmContext::with_message_id([0; 32]), bought, asset.into()).expect("Expected Ok");
// Check whether a correct amount of unused assets is returned
assert_ok!(
unused_assets.ensure_contains(&(asset_multilocation, asset_amount_extra).into())
Expand Down Expand Up @@ -184,12 +184,14 @@ fn test_asset_xcm_trader_with_refund() {

let asset: MultiAsset = (asset_multilocation, amount_bought).into();

let ctx = XcmContext::with_message_id([0; 32]);

// Make sure buy_weight does not return an error
assert_ok!(trader.buy_weight(bought, asset.clone().into()));
assert_ok!(trader.buy_weight(&ctx, bought, asset.clone().into()));

// Make sure again buy_weight does return an error
// This assert relies on the fact, that we use `TakeFirstAssetTrader` in `WeightTrader` tuple chain, which cannot be called twice
assert_noop!(trader.buy_weight(bought, asset.into()), XcmError::TooExpensive);
assert_noop!(trader.buy_weight(&ctx, bought, asset.into()), XcmError::TooExpensive);

// We actually use half of the weight
let weight_used = bought / 2;
Expand All @@ -198,7 +200,7 @@ fn test_asset_xcm_trader_with_refund() {
let amount_refunded = WeightToFee::weight_to_fee(&(bought - weight_used));

assert_eq!(
trader.refund_weight(bought - weight_used),
trader.refund_weight(&ctx, bought - weight_used),
Some((asset_multilocation, amount_refunded).into())
);

Expand Down Expand Up @@ -262,7 +264,7 @@ fn test_asset_xcm_trader_refund_not_possible_since_amount_less_than_ed() {
let asset: MultiAsset = (asset_multilocation, amount_bought).into();

// Buy weight should return an error
assert_noop!(trader.buy_weight(bought, asset.into()), XcmError::TooExpensive);
assert_noop!(trader.buy_weight(&XcmContext::with_message_id([0; 32]), bought, asset.into()), XcmError::TooExpensive);

// not credited since the ED is higher than this value
assert_eq!(Assets::balance(1, AccountId::from(ALICE)), 0);
Expand Down Expand Up @@ -313,17 +315,17 @@ fn test_that_buying_ed_refund_does_not_refund() {
// We know we will have to buy at least ED, so lets make sure first it will
// fail with a payment of less than ED
let asset: MultiAsset = (asset_multilocation, amount_bought).into();
assert_noop!(trader.buy_weight(bought, asset.into()), XcmError::TooExpensive);
assert_noop!(trader.buy_weight(&XcmContext::with_message_id([0; 32]), bought, asset.into()), XcmError::TooExpensive);

// Now lets buy ED at least
let asset: MultiAsset = (asset_multilocation, ExistentialDeposit::get()).into();

// Buy weight should work
assert_ok!(trader.buy_weight(bought, asset.into()));
assert_ok!(trader.buy_weight(&XcmContext::with_message_id([0; 32]), bought, asset.into()));

// Should return None. We have a specific check making sure we dont go below ED for
// drop payment
assert_eq!(trader.refund_weight(bought), None);
assert_eq!(trader.refund_weight(&XcmContext::with_message_id([0; 32]), bought), None);

// Drop trader
drop(trader);
Expand Down Expand Up @@ -384,7 +386,7 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
let asset: MultiAsset = (asset_multilocation, asset_amount_needed).into();

// Make sure again buy_weight does return an error
assert_noop!(trader.buy_weight(bought, asset.into()), XcmError::TooExpensive);
assert_noop!(trader.buy_weight(&XcmContext::with_message_id([0; 32]), bought, asset.into()), XcmError::TooExpensive);

// Drop trader
drop(trader);
Expand Down
12 changes: 3 additions & 9 deletions parachains/runtimes/assets/asset-hub-westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,19 @@ mod weights;
pub mod xcm_config;

use crate::xcm_config::{TrustBackedAssetsPalletLocation, UniversalLocation};
use pallet_asset_conversion_tx_payment::AssetConversionAdapter;
use assets_common::local_and_foreign_assets::{LocalAndForeignAssets, MultiLocationConverter};
use codec::{Decode, Encode, MaxEncodedLen};
use constants::{currency::*, fee::WeightToFee};
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
use frame_support::{construct_runtime, dispatch::DispatchClass, ord_parameter_types, parameter_types, traits::{
tokens::nonfungibles_v2::Inspect, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32,
ConstU64, ConstU8, InstanceFilter,
}, weights::{ConstantMultiplier, Weight}, BoundedVec, PalletId, RuntimeDebug, ensure};
use frame_support::traits::fungible;
use frame_support::traits::tokens::ConversionToAssetBalance;
}, weights::{ConstantMultiplier, Weight}, BoundedVec, PalletId, RuntimeDebug};
use frame_system::{
limits::{BlockLength, BlockWeights},
EnsureRoot, EnsureSigned, EnsureSignedBy,
};
use pallet_asset_conversion::MultiAssetIdConverter;
use pallet_asset_conversion_tx_payment::AssetConversionAdapter;
use pallet_asset_conversion_tx_payment::InitialPayment::Asset;
use pallet_assets::ConversionError;
use pallet_nfts::PalletFeatures;
pub use parachains_common as common;
use parachains_common::{
Expand All @@ -56,7 +51,7 @@ use parachains_common::{
};
use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{create_runtime_str, generic, impl_opaque_keys, traits::{AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, Verify}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, Permill, FixedPointOperand, FixedU128, FixedPointNumber};
use sp_runtime::{create_runtime_str, generic, impl_opaque_keys, traits::{AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, Verify}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, Permill};
use sp_std::prelude::*;
#[cfg(feature = "std")]
use sp_version::NativeVersion;
Expand All @@ -75,7 +70,6 @@ use assets_common::{
foreign_creators::ForeignCreators, matching::FromSiblingParachain, MultiLocationForAssetId,
};
use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
use sp_runtime::traits::Zero;
use xcm_executor::XcmExecutor;

use crate::xcm_config::ForeignCreatorsSovereignAccountOf;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use super::{
ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
};
use crate::{ForeignAssets};
use crate::ForeignAssets;
use assets_common::matching::{
FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus,
};
Expand All @@ -27,7 +27,6 @@ use frame_support::{
traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess},
};
use frame_system::EnsureRoot;
use pallet_asset_conversion_tx_payment::AssetConversionAdapter;
use pallet_xcm::XcmPassthrough;
use parachains_common::{impls::ToStakingPot, xcm_config::AssetFeeAsExistentialDepositMultiplier};
use polkadot_parachain::primitives::Sibling;
Expand Down Expand Up @@ -443,12 +442,10 @@ impl xcm_executor::Config for XcmConfig {
type Trader = (
UsingComponents<WeightToFee, WestendLocation, AccountId, Balances, ToStakingPot<Runtime>>,
cumulus_primitives_utility::SwapFirstAssetTrader<
AccountId,
LocationToAccountId,
Balance,
Runtime,
LocationToAccountId,
pallet_asset_conversion::Pallet<Runtime>,
WeightToFee,
AssetConversionAdapter<Balance, AssetConversion>,
MultiAssetsConvertedConcreteId,
LocalAndForeignAssets<Assets, ForeignAssets, TrustBackedAssetsPalletLocation>,
cumulus_primitives_utility::XcmFeesTo32ByteAccount<
Expand Down
3 changes: 2 additions & 1 deletion primitives/utility/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ log = { version = "0.4.19", default-features = false }

# Substrate
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
pallet-asset-conversion-tx-payment = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
pallet-asset-conversion = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
Expand All @@ -30,6 +30,7 @@ default = [ "std" ]
std = [
"codec/std",
"frame-support/std",
"pallet-asset-conversion/std",
"sp-runtime/std",
"sp-std/std",
"sp-io/std",
Expand Down
124 changes: 44 additions & 80 deletions primitives/utility/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ use frame_support::{
},
weights::Weight,
};
use pallet_asset_conversion_tx_payment::OnChargeAssetTransaction;
use frame_support::traits::fungibles::SwapNative;
use pallet_asset_conversion::{Swap, Config, MultiAssetIdConverter};
use polkadot_runtime_common::xcm_sender::ConstantPrice;
use sp_runtime::{traits::Saturating, SaturatedConversion};
use sp_runtime::traits::CheckedSub;
use sp_std::{marker::PhantomData, prelude::*};
use xcm::{latest::prelude::*, WrapVersion};
use xcm_builder::TakeRevenue;
Expand Down Expand Up @@ -275,36 +275,33 @@ impl<
/// Contains information to handle refund/payment for xcm-execution
#[derive(Clone, Eq, PartialEq, Debug)]
struct SwapAssetTraderRefunder {
// The concrete asset containing the asset location and outstanding balance
// The concrete asset containing the asset location and any leftover balance
outstanding_concrete_asset: MultiAsset,
}

pub struct SwapFirstAssetTrader<
AccountId,
AccountIdConverter: ConvertLocation<AccountId>,
Balance,
Runtime: pallet_asset_conversion_tx_payment::Config,
WeightToFee: frame_support::weights::WeightToFee<Balance = Balance>,
ChargeAssetTransaction: OnChargeAssetTransaction<Runtime>,
T: Config,
AccountIdConverter: ConvertLocation<T::AccountId>,
SWP: Swap<T::AccountId, T::HigherPrecisionBalance, T::MultiAssetId>,
WeightToFee: frame_support::weights::WeightToFee<Balance = T::Balance>,
Matcher: MatchesFungibles<ConcreteAssets::AssetId, ConcreteAssets::Balance>,
ConcreteAssets: fungibles::Mutate<AccountId> + fungibles::Balanced<AccountId>,
ConcreteAssets: fungibles::Mutate<T::AccountId> + fungibles::Balanced<T::AccountId>,
HandleRefund: TakeRevenue,
>(
Option<SwapAssetTraderRefunder>,
PhantomData<(AccountId, AccountIdConverter, Balance, Runtime, WeightToFee, ChargeAssetTransaction, Matcher, ConcreteAssets, HandleRefund)>,
PhantomData<(T, AccountIdConverter, SWP, WeightToFee, Matcher, ConcreteAssets, HandleRefund)>,
);

impl<
AccountId,
AccountIdConverter: ConvertLocation<AccountId>,
Balance,
Runtime: pallet_asset_conversion_tx_payment::Config,
WeightToFee: frame_support::weights::WeightToFee<Balance = Balance>,
ChargeAssetTransaction: OnChargeAssetTransaction<Runtime>,
T: Config,
AccountIdConverter: ConvertLocation<T::AccountId>,
SWP: Swap<T::AccountId, T::HigherPrecisionBalance, T::MultiAssetId>,
WeightToFee: frame_support::weights::WeightToFee<Balance = T::Balance>,
Matcher: MatchesFungibles<ConcreteAssets::AssetId, ConcreteAssets::Balance>,
ConcreteAssets: fungibles::Mutate<AccountId> + fungibles::Balanced<AccountId>,
ConcreteAssets: fungibles::Mutate<T::AccountId> + fungibles::Balanced<T::AccountId>,
HandleRefund: TakeRevenue,
> WeightTrader
for SwapFirstAssetTrader<AccountId, AccountIdConverter, Balance, Runtime, WeightToFee, ChargeAssetTransaction, Matcher, ConcreteAssets, HandleRefund>
for SwapFirstAssetTrader<T, AccountIdConverter, SWP, WeightToFee, Matcher, ConcreteAssets, HandleRefund>
{
fn new() -> Self {
Self(None, PhantomData)
Expand Down Expand Up @@ -334,90 +331,57 @@ for SwapFirstAssetTrader<AccountId, AccountIdConverter, Balance, Runtime, Weight
// Take the first multiasset from the selected MultiAssets
let first = multiassets.get(0).ok_or(XcmError::AssetNotFound)?;

// Get the local asset id in which we can pay for fees
let (local_asset_id, _) =
// Get the multi asset id in which we can pay for fees
let (multi_id, local_asset_balance) =
Matcher::matches_fungibles(first).map_err(|_| XcmError::AssetNotFound)?;

let fee = WeightToFee::weight_to_fee(&weight);

let acc = AccountIdConverter::convert_location(&ctx.origin.unwrap()).unwrap();

// Call ChargeAssetTransaction::withdraw_fee
// ...
// TODO
//
let (_, native_asset_acquired, asset_consumed) = ChargeAssetTransaction::withdraw_fee(
acc,
// Downstream functions IGNORE this runtime call argument, what is a proper value?
<MockRuntimeCall>,
// Downstream functions IGNORE this runtime dispatch info argument, what is a proper value?
<MockDispatchInfo>,
local_asset_id,
fee,
0
).unwrap();
let amount_taken = SWP::swap_tokens_for_exact_tokens(
acc.clone(),
vec![multi_id, T::MultiAssetIdConverter::get_native()],
T::HigherPrecisionBalance::from(fee),
None,
acc.clone(),
true
).map_err(|_| XcmError::AssetNotFound)?;

// Convert to the same kind of multiasset, with the required fungible balance
let required = first.id.into_multiasset(asset_balance.into());
// Convert payment to hpb
let payment_balance = T::HigherPrecisionBalance::from(local_asset_balance);

// Substract payment
let unused = payment.checked_sub(required.clone()).map_err(|_| XcmError::TooExpensive)?;
// Substract amount_taken from payment_balance
let unused = payment_balance.checked_sub(&amount_taken).ok_or(XcmError::TooExpensive)?;

// record weight and multiasset
let unused_asset: T::Balance = unused.try_into().map_err(|_| XcmError::AssetNotFound)?;

// Record outstanding asset
self.0 = Some(SwapAssetTraderRefunder {
outstanding_concrete_asset: required,
outstanding_concrete_asset: first.clone(),
});

Ok(unused)
Ok(unused_asset)
}

fn refund_weight(&mut self, ctx: &XcmContext, weight: Weight) -> Option<MultiAsset> {
log::trace!(target: "xcm::weight", "SwapFirstAssetTrader::refund_weight weight: {:?}", weight);

if let Some(SwapAssetTraderRefunder {
outstanding_concrete_asset: MultiAsset { id, fun },
}) = self.0.clone()
{
// Get the local asset id in which we can refund fees
let (local_asset_id, outstanding_balance) =
Matcher::matches_fungibles(&(id, fun).into()).ok()?;

// Re-calculate asset swap from native to MultiAsset provided
// ...
// TODO

// Convert balances into u128
let outstanding_minus_substracted: u128 =
outstanding_minus_substracted.saturated_into();
let asset_balance: u128 = asset_balance.saturated_into();

// Construct outstanding_concrete_asset with the same location id and substracted balance
let outstanding_concrete_asset: MultiAsset = (id, outstanding_minus_substracted).into();

// Override SwapAssetTraderRefunder
self.0 = Some(SwapAssetTraderRefunder { outstanding_concrete_asset });

// Only refund if positive
if asset_balance > 0 {
return Some((id, asset_balance).into())
}
}
// TODO: swap back the weight with swap_exact_tokens_for_tokens

None
}
}

impl<
AccountId,
AccountIdConverter: ConvertLocation<AccountId>,
Balance,
Runtime: pallet_asset_conversion_tx_payment::Config,
WeightToFee: frame_support::weights::WeightToFee<Balance = Balance>,
ChargeAssetTransaction: OnChargeAssetTransaction<Runtime>,
T: Config,
AccountIdConverter: ConvertLocation<T::AccountId>,
SWP: Swap<T::AccountId, T::HigherPrecisionBalance, T::MultiAssetId>,
WeightToFee: frame_support::weights::WeightToFee<Balance = T::Balance>,
Matcher: MatchesFungibles<ConcreteAssets::AssetId, ConcreteAssets::Balance>,
ConcreteAssets: fungibles::Mutate<AccountId> + fungibles::Balanced<AccountId>,
ConcreteAssets: fungibles::Mutate<T::AccountId> + fungibles::Balanced<T::AccountId>,
HandleRefund: TakeRevenue,
> Drop for SwapFirstAssetTrader<AccountId, AccountIdConverter, Balance, Runtime, WeightToFee, ChargeAssetTransaction, Matcher, ConcreteAssets, HandleRefund>
> Drop for SwapFirstAssetTrader<T, AccountIdConverter, SWP, WeightToFee, Matcher, ConcreteAssets, HandleRefund>
{
fn drop(&mut self) {
if let Some(asset_trader) = self.0.clone() {
Expand Down Expand Up @@ -692,9 +656,9 @@ mod tests {
let weight_to_buy = Weight::from_parts(1_000, 1_000);

// lets do first call (success)
assert_ok!(trader.buy_weight(weight_to_buy, payment.clone()));
assert_ok!(trader.buy_weight(&XcmContext::with_message_id([0; 32]), weight_to_buy, payment.clone()));

// lets do second call (error)
assert_eq!(trader.buy_weight(weight_to_buy, payment), Err(XcmError::NotWithdrawable));
assert_eq!(trader.buy_weight(&XcmContext::with_message_id([0; 32]), weight_to_buy, payment), Err(XcmError::NotWithdrawable));
}
}

0 comments on commit b3adbf6

Please sign in to comment.