diff --git a/Cargo.lock b/Cargo.lock index baf99392cefb..ce7da53dc127 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1077,6 +1077,7 @@ dependencies = [ "frame-support 28.0.0", "frame-system 28.0.0", "hex-literal", + "pallet-asset-conversion 10.0.0", "pallet-assets 29.1.0", "pallet-balances 28.0.0", "pallet-collator-selection 9.0.0", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index 94f37767cfea..486bde6cca00 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -1474,5 +1474,5 @@ fn location_conversion_works() { #[test] fn xcm_payment_api_works() { - asset_test_utils::test_cases::xcm_payment_api_works::(); + asset_test_utils::test_cases::xcm_payment_api_works::(); } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index cd4cdfff3069..4820fe3f314f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -1449,5 +1449,5 @@ fn location_conversion_works() { #[test] fn xcm_payment_api_works() { - asset_test_utils::test_cases::xcm_payment_api_works::(); + asset_test_utils::test_cases::xcm_payment_api_works::(); } diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index c1f29d2c3d9d..6b827cdc4c71 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -16,6 +16,7 @@ codec = { features = ["derive", "max-encoded-len"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } pallet-assets = { workspace = true } +pallet-asset-conversion = { workspace = true } pallet-balances = { workspace = true } pallet-timestamp = { workspace = true } pallet-session = { workspace = true } diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs index 5aa5c6ad9cb3..b15fa96cdf2e 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -39,6 +39,7 @@ use sp_runtime::{ }; use xcm::{latest::prelude::*, VersionedAssets}; use xcm_executor::{traits::ConvertLocation, XcmExecutor}; +use xcm_runtime_apis::fees::{Error as XcmPaymentApiError, runtime_decl_for_xcm_payment_api::XcmPaymentApiV1}; type RuntimeHelper = parachains_runtimes_test_utils::RuntimeHelper; @@ -1585,25 +1586,40 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< }) } -use xcm_runtime_apis::fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1; - -pub fn xcm_payment_api_works() +pub fn xcm_payment_api_works() where Runtime: XcmPaymentApiV1 - + frame_system::Config - + pallet_balances::Config + + frame_system::Config< + RuntimeOrigin = RuntimeOrigin, + AccountId = AccountId + > + + pallet_balances::Config + pallet_session::Config + pallet_xcm::Config + parachain_info::Config + pallet_collator_selection::Config + cumulus_pallet_parachain_system::Config + cumulus_pallet_xcmp_queue::Config - + pallet_timestamp::Config, + + pallet_timestamp::Config + + pallet_assets::Config< + pallet_assets::Instance1, + AssetId = u32, + Balance = ::Balance + > + + pallet_asset_conversion::Config< + AssetKind = xcm::v5::Location, + Balance = ::Balance + >, ValidatorIdOf: From>, + RuntimeOrigin: OriginTrait::AccountId>, + <::Lookup as StaticLookup>::Source: + From<::AccountId>, + Block: BlockT, { use xcm::prelude::*; ExtBuilder::::default().build().execute_with(|| { + let test_account = AccountId::from([0u8; 32]); let transfer_amount = 100u128; let xcm_to_weigh = Xcm::::builder_unsafe() .withdraw_asset((Here, transfer_amount)) @@ -1611,14 +1627,70 @@ where .deposit_asset(AllCounted(1), [1u8; 32]) .build(); let versioned_xcm_to_weigh = VersionedXcm::from(xcm_to_weigh.clone().into()); + + // We first try calling it with a lower XCM version. let lower_version_xcm_to_weigh = versioned_xcm_to_weigh.into_version(XCM_VERSION - 1).unwrap(); let xcm_weight = Runtime::query_xcm_weight(lower_version_xcm_to_weigh); assert!(xcm_weight.is_ok()); - let native_token = VersionedAssetId::from(AssetId(Parent.into())); - let lower_version_native_token = native_token.into_version(XCM_VERSION - 1).unwrap(); + let native_token: Location = Parent.into(); + let native_token_versioned = VersionedAssetId::from(AssetId(native_token.clone())); + let lower_version_native_token = native_token_versioned.clone().into_version(XCM_VERSION - 1).unwrap(); let execution_fees = Runtime::query_weight_to_asset_fee(xcm_weight.unwrap(), lower_version_native_token); assert!(execution_fees.is_ok()); + + // We need some balance to create an asset. + assert_ok!(pallet_balances::Pallet::::mint_into( + &test_account, + 3_000_000_000_000, + )); + + // Now we try to use an asset that's not in a pool. + let asset_id = 1984u32; // USDT. + let asset_not_in_pool: Location = (PalletInstance(50), GeneralIndex(asset_id.into())).into(); + assert_ok!(pallet_assets::Pallet::::create( + RuntimeOrigin::signed(test_account.clone()), + asset_id.into(), + test_account.clone().into(), + 1000 + )); + let execution_fees = + Runtime::query_weight_to_asset_fee(xcm_weight.unwrap(), asset_not_in_pool.clone().into()); + assert_eq!(execution_fees, Err(XcmPaymentApiError::AssetNotFound)); + + // We add it to a pool with native. + assert_ok!(pallet_asset_conversion::Pallet::::create_pool( + RuntimeOrigin::signed(test_account.clone()), + native_token.clone().try_into().unwrap(), + asset_not_in_pool.clone().try_into().unwrap() + )); + let execution_fees = + Runtime::query_weight_to_asset_fee(xcm_weight.unwrap(), asset_not_in_pool.clone().into()); + // Still not enough because it doesn't have any liquidity. + assert_eq!(execution_fees, Err(XcmPaymentApiError::AssetNotFound)); + + // We mint some of the asset... + assert_ok!(pallet_assets::Pallet::::mint( + RuntimeOrigin::signed(test_account.clone()), + asset_id.into(), + test_account.clone().into(), + 3_000_000_000_000, + )); + // ...so we can add liquidity to the pool. + assert_ok!(pallet_asset_conversion::Pallet::::add_liquidity( + RuntimeOrigin::signed(test_account.clone()), + native_token.try_into().unwrap(), + asset_not_in_pool.clone().try_into().unwrap(), + 1_000_000_000_000, + 2_000_000_000_000, + 0, + 0, + test_account + )); + let execution_fees = + Runtime::query_weight_to_asset_fee(xcm_weight.unwrap(), asset_not_in_pool.into()); + // Now it works! + assert_ok!(execution_fees); }); }