Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
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
67 changes: 56 additions & 11 deletions cumulus/parachains/integration-tests/emulated/common/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ macro_rules! test_dry_run_transfer_across_pk_bridge {
macro_rules! test_xcm_fee_querying_apis_work_for_asset_hub {
( $asset_hub:ty ) => {
$crate::macros::paste::paste! {
use emulated_integration_tests_common::USDT_ID;
use emulated_integration_tests_common::{USDT_ID, RESERVABLE_ASSET_ID};
use xcm_runtime_apis::fees::{Error as XcmPaymentApiError, runtime_decl_for_xcm_payment_api::XcmPaymentApiV1};

$asset_hub::execute_with(|| {
Expand Down Expand Up @@ -713,12 +713,12 @@ macro_rules! test_xcm_fee_querying_apis_work_for_asset_hub {
.build();
let weight = Runtime::query_xcm_weight(VersionedXcm::from(program)).unwrap();
let fee_in_wnd = Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(AssetId(wnd.clone()))).unwrap();
// Assets not in a pool don't work.
assert!(Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(AssetId(Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(1)])))).is_err());
let fee_in_usdt_fail = Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(AssetId(usdt.clone())));
// Weight to asset fee fails because there's not enough asset in the pool.
// We just created it, there's none.
assert_eq!(fee_in_usdt_fail, Err(XcmPaymentApiError::AssetNotFound));

// USDT is sufficient asset, so it passes even if there is not enough liquidity yet.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since #8376 was merged recently, sufficient assets can no longer directly buy weight and also have to go through liquidity pool to work.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll revert this commit then. Merging master should fix the tests instead

// We just created the pool, there's none.
let fee_in_usdt_no_liq = Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(AssetId(usdt.clone())));
assert_ok!(fee_in_usdt_no_liq);

// We add some.
assert_ok!(Assets::mint(
RuntimeOrigin::signed(sender.clone()),
Expand All @@ -729,18 +729,63 @@ macro_rules! test_xcm_fee_querying_apis_work_for_asset_hub {
// We make 1 WND = 4 USDT.
assert_ok!(AssetConversion::add_liquidity(
RuntimeOrigin::signed(sender.clone()),
Box::new(wnd),
Box::new(wnd.clone()),
Box::new(usdt.clone()),
1_000_000_000_000,
4_000_000_000_000,
0,
0,
sender.clone().into()
));
// The fee has changed after the liquidity is provided
let fee_in_usdt_with_liq = Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(AssetId(usdt.clone())));
assert_ok!(fee_in_usdt_with_liq);
assert_ne!(fee_in_usdt_no_liq.unwrap(), fee_in_usdt_with_liq.unwrap());
assert!(fee_in_usdt_with_liq.unwrap() > fee_in_wnd);

// Setup pool between WND and the Reservable asset
let reservable = Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(RESERVABLE_ASSET_ID.into())]);
assert_ok!(AssetConversion::create_pool(
RuntimeOrigin::signed(sender.clone()),
Box::new(wnd.clone()),
Box::new(reservable.clone()),
));

let acceptable_payment_assets = Runtime::query_acceptable_payment_assets(XCM_VERSION).unwrap();
assert_eq!(acceptable_payment_assets, vec![
VersionedAssetId::from(AssetId(wnd.clone())),
VersionedAssetId::from(AssetId(usdt)),
VersionedAssetId::from(AssetId(reservable.clone())),
]);

// Assets not in a pool don't work.
// Weight to asset fee fails because there's not enough (insufficient) asset in the pool.
// We just created it, there's none.
let fee_in_reservable_fail = Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(AssetId(reservable.clone())));
assert_eq!(fee_in_reservable_fail , Err(XcmPaymentApiError::AssetNotFound));

// We add some.
assert_ok!(Assets::mint(
RuntimeOrigin::signed(sender.clone()),
RESERVABLE_ASSET_ID.into(),
sender.clone().into(),
9_000_000_000_000
));
// We make 1 WND = 7 Reservable Asset.
assert_ok!(AssetConversion::add_liquidity(
RuntimeOrigin::signed(sender.clone()),
Box::new(wnd),
Box::new(reservable.clone()),
1_000_000_000_000,
7_000_000_000_000,
0,
0,
sender.into()
));
// Now it works.
let fee_in_usdt = Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(AssetId(usdt)));
assert_ok!(fee_in_usdt);
assert!(fee_in_usdt.unwrap() > fee_in_wnd);
let fee_in_reservable = Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(AssetId(reservable)));
assert_ok!(fee_in_reservable);
assert!(fee_in_reservable.unwrap() > fee_in_wnd);
});
}
};
Expand Down
34 changes: 6 additions & 28 deletions cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ use frame_support::{
AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8,
ConstantStoragePrice, EitherOfDiverse, Equals, InstanceFilter, TransformOrigin,
},
weights::{ConstantMultiplier, Weight, WeightToFee as _},
weights::{ConstantMultiplier, Weight},
BoundedVec, PalletId,
};
use frame_system::{
Expand Down Expand Up @@ -1555,33 +1555,11 @@ impl_runtime_apis! {
}

fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result<u128, XcmPaymentApiError> {
let native_asset = xcm_config::TokenLocation::get();
let fee_in_native = WeightToFee::weight_to_fee(&weight);
let latest_asset_id: Result<AssetId, ()> = asset.clone().try_into();
match latest_asset_id {
Ok(asset_id) if asset_id.0 == native_asset => {
// for native token
Ok(fee_in_native)
},
Ok(asset_id) => {
// Try to get current price of `asset_id` in `native_asset`.
if let Ok(Some(swapped_in_native)) = assets_common::PoolAdapter::<Runtime>::quote_price_tokens_for_exact_tokens(
asset_id.0.clone(),
native_asset,
fee_in_native,
true, // We include the fee.
) {
Ok(swapped_in_native)
} else {
log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!");
Err(XcmPaymentApiError::AssetNotFound)
}
},
Err(_) => {
log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!");
Err(XcmPaymentApiError::VersionedConversionFailed)
}
}
use crate::xcm_config::XcmConfig;

type Trader = <XcmConfig as xcm_executor::Config>::Trader;

PolkadotXcm::query_weight_to_asset_fee::<Trader>(weight, asset)
}

fn query_xcm_weight(message: VersionedXcm<()>) -> Result<Weight, XcmPaymentApiError> {
Expand Down
60 changes: 12 additions & 48 deletions cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ use asset_test_utils::{
ExtBuilder, GovernanceOrigin, SlotDurations,
};
use codec::{Decode, Encode};
use core::ops::Mul;
use cumulus_primitives_utility::ChargeWeightInFungibles;
use frame_support::{
assert_noop, assert_ok, parameter_types,
Expand Down Expand Up @@ -93,52 +92,6 @@ fn slot_durations() -> SlotDurations {
}
}

fn setup_pool_for_paying_fees_with_foreign_assets(
(foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance): (
AccountId,
Location,
Balance,
),
) {
let existential_deposit = ExistentialDeposit::get();

// setup a pool to pay fees with `foreign_asset_id_location` tokens
let pool_owner: AccountId = [14u8; 32].into();
let native_asset = Location::parent();
let pool_liquidity: Balance =
existential_deposit.max(foreign_asset_id_minimum_balance).mul(100_000);

let _ = Balances::force_set_balance(
RuntimeOrigin::root(),
pool_owner.clone().into(),
(existential_deposit + pool_liquidity).mul(2).into(),
);

assert_ok!(ForeignAssets::mint(
RuntimeOrigin::signed(foreign_asset_owner),
foreign_asset_id_location.clone().into(),
pool_owner.clone().into(),
(foreign_asset_id_minimum_balance + pool_liquidity).mul(2).into(),
));

assert_ok!(AssetConversion::create_pool(
RuntimeOrigin::signed(pool_owner.clone()),
Box::new(native_asset.clone().into()),
Box::new(foreign_asset_id_location.clone().into())
));

assert_ok!(AssetConversion::add_liquidity(
RuntimeOrigin::signed(pool_owner.clone()),
Box::new(native_asset.into()),
Box::new(foreign_asset_id_location.into()),
pool_liquidity,
pool_liquidity,
1,
1,
pool_owner,
));
}

#[test]
fn test_buy_and_refund_weight_in_native() {
ExtBuilder::<Runtime>::default()
Expand Down Expand Up @@ -1147,7 +1100,7 @@ mod asset_hub_rococo_tests {
1000000000000,
|| {
// setup pool for paying fees to touch `SwapFirstAssetTrader`
setup_pool_for_paying_fees_with_foreign_assets(foreign_asset_create_params);
asset_test_utils::test_cases::setup_pool_for_paying_fees_with_foreign_assets::<Runtime, RuntimeOrigin>(ExistentialDeposit::get(), foreign_asset_create_params);
// staking pot account for collecting local native fees from `BuyExecution`
let _ = Balances::force_set_balance(RuntimeOrigin::root(), StakingPot::get().into(), ExistentialDeposit::get());
// prepare bridge configuration
Expand Down Expand Up @@ -1663,11 +1616,22 @@ fn xcm_payment_api_works() {
RuntimeCall,
RuntimeOrigin,
Block,
WeightToFee,
>();
asset_test_utils::test_cases::xcm_payment_api_with_pools_works::<
Runtime,
RuntimeCall,
RuntimeOrigin,
Block,
WeightToFee,
>();

asset_test_utils::test_cases::xcm_payment_api_foreign_asset_pool_works::<
Runtime,
RuntimeCall,
RuntimeOrigin,
LocationToAccountId,
Block,
WeightToFee,
>(ExistentialDeposit::get(), WESTEND_GENESIS_HASH);
}
34 changes: 6 additions & 28 deletions cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use frame_support::{
AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8,
ConstantStoragePrice, Equals, InstanceFilter, Nothing, TransformOrigin,
},
weights::{ConstantMultiplier, Weight, WeightToFee as _},
weights::{ConstantMultiplier, Weight},
BoundedVec, PalletId,
};
use frame_system::{
Expand Down Expand Up @@ -1692,33 +1692,11 @@ impl_runtime_apis! {
}

fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result<u128, XcmPaymentApiError> {
let native_asset = xcm_config::WestendLocation::get();
let fee_in_native = WeightToFee::weight_to_fee(&weight);
let latest_asset_id: Result<AssetId, ()> = asset.clone().try_into();
match latest_asset_id {
Ok(asset_id) if asset_id.0 == native_asset => {
// for native asset
Ok(fee_in_native)
},
Ok(asset_id) => {
// Try to get current price of `asset_id` in `native_asset`.
if let Ok(Some(swapped_in_native)) = assets_common::PoolAdapter::<Runtime>::quote_price_tokens_for_exact_tokens(
asset_id.0.clone(),
native_asset,
fee_in_native,
true, // We include the fee.
) {
Ok(swapped_in_native)
} else {
log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!");
Err(XcmPaymentApiError::AssetNotFound)
}
},
Err(_) => {
log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!");
Err(XcmPaymentApiError::VersionedConversionFailed)
}
}
use crate::xcm_config::XcmConfig;

type Trader = <XcmConfig as xcm_executor::Config>::Trader;

PolkadotXcm::query_weight_to_asset_fee::<Trader>(weight, asset)
}

fn query_xcm_weight(message: VersionedXcm<()>) -> Result<Weight, XcmPaymentApiError> {
Expand Down
61 changes: 13 additions & 48 deletions cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use parachains_common::{AccountId, AssetIdForTrustBackedAssets, AuraId, Balance}
use sp_consensus_aura::SlotDuration;
use sp_core::crypto::Ss58Codec;
use sp_runtime::{traits::MaybeEquivalence, Either};
use std::{convert::Into, ops::Mul};
use std::convert::Into;
use testnet_parachains_constants::westend::{consensus::*, currency::UNITS, fee::WeightToFee};
use xcm::latest::{
prelude::{Assets as XcmAssets, *},
Expand Down Expand Up @@ -94,52 +94,6 @@ fn slot_durations() -> SlotDurations {
}
}

fn setup_pool_for_paying_fees_with_foreign_assets(
(foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance): (
AccountId,
xcm::v5::Location,
Balance,
),
) {
let existential_deposit = ExistentialDeposit::get();

// setup a pool to pay fees with `foreign_asset_id_location` tokens
let pool_owner: AccountId = [14u8; 32].into();
let native_asset = xcm::v5::Location::parent();
let pool_liquidity: Balance =
existential_deposit.max(foreign_asset_id_minimum_balance).mul(100_000);

let _ = Balances::force_set_balance(
RuntimeOrigin::root(),
pool_owner.clone().into(),
(existential_deposit + pool_liquidity).mul(2).into(),
);

assert_ok!(ForeignAssets::mint(
RuntimeOrigin::signed(foreign_asset_owner),
foreign_asset_id_location.clone().into(),
pool_owner.clone().into(),
(foreign_asset_id_minimum_balance + pool_liquidity).mul(2).into(),
));

assert_ok!(AssetConversion::create_pool(
RuntimeOrigin::signed(pool_owner.clone()),
Box::new(native_asset.clone().into()),
Box::new(foreign_asset_id_location.clone().into())
));

assert_ok!(AssetConversion::add_liquidity(
RuntimeOrigin::signed(pool_owner.clone()),
Box::new(native_asset.into()),
Box::new(foreign_asset_id_location.into()),
pool_liquidity,
pool_liquidity,
1,
1,
pool_owner,
));
}

#[test]
fn test_buy_and_refund_weight_in_native() {
ExtBuilder::<Runtime>::default()
Expand Down Expand Up @@ -1253,7 +1207,7 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_pool_s
1000000000000,
|| {
// setup pool for paying fees to touch `SwapFirstAssetTrader`
setup_pool_for_paying_fees_with_foreign_assets(foreign_asset_create_params);
asset_test_utils::test_cases::setup_pool_for_paying_fees_with_foreign_assets::<Runtime, RuntimeOrigin>(ExistentialDeposit::get(), foreign_asset_create_params);
// staking pot account for collecting local native fees from `BuyExecution`
let _ = Balances::force_set_balance(RuntimeOrigin::root(), StakingPot::get().into(), ExistentialDeposit::get());
// prepare bridge configuration
Expand Down Expand Up @@ -1728,13 +1682,24 @@ fn xcm_payment_api_works() {
RuntimeCall,
RuntimeOrigin,
Block,
WeightToFee,
>();
asset_test_utils::test_cases::xcm_payment_api_with_pools_works::<
Runtime,
RuntimeCall,
RuntimeOrigin,
Block,
WeightToFee,
>();

asset_test_utils::test_cases::xcm_payment_api_foreign_asset_pool_works::<
Runtime,
RuntimeCall,
RuntimeOrigin,
LocationToAccountId,
Block,
WeightToFee,
>(ExistentialDeposit::get(), ROCOCO_GENESIS_HASH);
}

#[test]
Expand Down
Loading