diff --git a/Cargo.lock b/Cargo.lock index 01c68fa8d..51437bd0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4669,6 +4669,7 @@ dependencies = [ "substrate-wasm-builder", "system-parachains-constants", "xcm-emulator", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -8729,6 +8730,7 @@ dependencies = [ "sp-runtime", "sp-std", "staging-xcm", + "staging-xcm-builder", ] [[package]] @@ -8904,6 +8906,7 @@ dependencies = [ "staging-xcm-builder", "staging-xcm-executor", "substrate-wasm-builder", + "xcm-fee-payment-runtime-api", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8035c08fc..52055e6ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -187,6 +187,7 @@ xcm-builder = { version = "14.0.0", package = 'staging-xcm-builder', default-fea xcm-executor = { version = "14.0.0", package = 'staging-xcm-executor', default-features = false } polkadot-runtime-common = { version = "14.0.0", default-features = false } polkadot-primitives = { version = "14.0.0", default-features = false } +xcm-fee-payment-runtime-api = { version = "0.4.0", default-features = false } # Cumulus (with default disabled) cumulus-pallet-aura-ext = { version = "0.14.0", default-features = false } diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 56c4da2c2..cd30e130f 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -81,6 +81,7 @@ pallet-aura.workspace = true pallet-session.workspace = true pallet-proxy-bonding.workspace = true pallet-skip-feeless-payment.workspace = true +xcm-fee-payment-runtime-api.workspace = true # Runtimes polkadot-runtime.workspace = true diff --git a/integration-tests/src/tests/mod.rs b/integration-tests/src/tests/mod.rs index 48af78f42..c0e1a51e1 100644 --- a/integration-tests/src/tests/mod.rs +++ b/integration-tests/src/tests/mod.rs @@ -23,6 +23,7 @@ mod governance; mod oracle; mod otm_edge_cases; mod reserve_backed_transfers; +mod runtime_apis; mod transaction_payment; mod vest; mod xcm_config; diff --git a/integration-tests/src/tests/runtime_apis.rs b/integration-tests/src/tests/runtime_apis.rs new file mode 100644 index 000000000..02115c379 --- /dev/null +++ b/integration-tests/src/tests/runtime_apis.rs @@ -0,0 +1,83 @@ +use crate::{constants::*, *}; + +mod xcm_payment_api { + use super::*; + use sp_arithmetic::FixedU128; + use xcm::v4::Junctions::X3; + use xcm_fee_payment_runtime_api::fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1; + + #[test] + fn query_acceptable_payment_assets() { + PolimecNet::execute_with(|| { + let accepted_payment_assets = PolimecRuntime::query_acceptable_payment_assets(4u32).unwrap(); + assert_eq!( + accepted_payment_assets, + vec![ + VersionedAssetId::V4(AssetId(Location { parents: 0, interior: Here },),), + VersionedAssetId::V4(AssetId(Location { parents: 1, interior: Here },),), + VersionedAssetId::V4(AssetId(Location { + parents: 1, + interior: X3([Parachain(1000,), PalletInstance(50,), GeneralIndex(1984,),].into(),), + },),), + VersionedAssetId::V4(AssetId(Location { + parents: 1, + interior: X3([Parachain(1000,), PalletInstance(50,), GeneralIndex(1337,),].into(),), + },),), + ] + ); + }); + } + + #[test] + fn query_weight_to_asset_fee() { + polimec::set_prices( + PricesBuilder::new() + .usdt(FixedU128::from_float(1.0f64)) + .plmc(FixedU128::from_float(0.5f64)) + .dot(FixedU128::from_float(10.0f64)) + .build(), + ); + + let compute_weight = Weight::from_parts(100_000_000, 20_000); + + // Native Asset + PolimecNet::execute_with(|| { + let plmc_fee = PolimecRuntime::query_weight_to_asset_fee( + compute_weight, + VersionedAssetId::V4(AssetId(Location { parents: 0, interior: Here })), + ) + .unwrap(); + dbg!(plmc_fee); + + let dot_fee = PolimecRuntime::query_weight_to_asset_fee( + compute_weight, + VersionedAssetId::V4(AssetId(Location { parents: 1, interior: Here })), + ) + .unwrap(); + dbg!(dot_fee); + + let usdt_fee = PolimecRuntime::query_weight_to_asset_fee( + compute_weight, + VersionedAssetId::V4(AssetId(Location { + parents: 1, + interior: X3([Parachain(1000), PalletInstance(50), GeneralIndex(1984)].into()), + })), + ) + .unwrap(); + dbg!(usdt_fee); + + // PLMC and dot have the same decimals, so a simple conversion is enough + assert_eq!(dot_fee, plmc_fee / 20); + // USDT has 6 decimals, so we need to divide by 10^(10-6)= 10_000 + assert_eq!(usdt_fee, plmc_fee / 2 / 10_000); + }); + } + + #[test] + fn query_xcm_weight() { + PolimecNet::execute_with(|| { + let xcm_weight = PolimecRuntime::query_xcm_weight().unwrap(); + assert_eq!(xcm_weight, 100_000_000); + }); + } +} diff --git a/pallets/dispenser/src/extensions.rs b/pallets/dispenser/src/extensions.rs index 17d700b4f..63a4689bd 100644 --- a/pallets/dispenser/src/extensions.rs +++ b/pallets/dispenser/src/extensions.rs @@ -19,7 +19,7 @@ use crate::{Call, Config}; use frame_support::{dispatch::DispatchInfo, pallet_prelude::*, traits::IsSubType}; use parity_scale_codec::{Decode, Encode}; -use scale_info::{TypeInfo}; +use scale_info::TypeInfo; use sp_runtime::traits::{DispatchInfoOf, Dispatchable, One, SignedExtension, Zero}; use sp_std::vec; /// Custom CheckNonce signed extension for Polimec Blockchain. Based on the CheckNonce signed extension from the FRAME. diff --git a/polimec-common/common/Cargo.toml b/polimec-common/common/Cargo.toml index 53dceb579..a500fe8f5 100644 --- a/polimec-common/common/Cargo.toml +++ b/polimec-common/common/Cargo.toml @@ -27,6 +27,7 @@ sp-std.workspace = true sp-runtime.workspace = true itertools.workspace = true xcm.workspace = true +xcm-builder.workspace = true [features] diff --git a/polimec-common/common/src/lib.rs b/polimec-common/common/src/lib.rs index c7d3472ca..caaaeddcf 100644 --- a/polimec-common/common/src/lib.rs +++ b/polimec-common/common/src/lib.rs @@ -23,6 +23,7 @@ use sp_runtime::{ }; use sp_std::prelude::*; pub use xcm::v4::{opaque::Xcm, Assets, Location, QueryId, SendError, SendResult, SendXcm, XcmHash}; +use xcm::{VersionedLocation, VersionedXcm}; pub mod credentials; @@ -239,6 +240,11 @@ impl SendXcm for DummyXcmSender { Ok([0u8; 32]) } } +impl xcm_builder::InspectMessageQueues for DummyXcmSender { + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { + vec![] + } +} pub trait ProvideAssetPrice { type AssetId; diff --git a/runtimes/polimec/Cargo.toml b/runtimes/polimec/Cargo.toml index 066821a28..ffd255e29 100644 --- a/runtimes/polimec/Cargo.toml +++ b/runtimes/polimec/Cargo.toml @@ -93,6 +93,7 @@ polkadot-runtime-common.workspace = true xcm.workspace = true xcm-builder.workspace = true xcm-executor.workspace = true +xcm-fee-payment-runtime-api.workspace = true # Cumulus cumulus-pallet-aura-ext.workspace = true diff --git a/runtimes/polimec/src/lib.rs b/runtimes/polimec/src/lib.rs index 17c185872..9c1e19663 100644 --- a/runtimes/polimec/src/lib.rs +++ b/runtimes/polimec/src/lib.rs @@ -20,7 +20,6 @@ // Make the WASM binary available. #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); - use core::ops::RangeInclusive; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; @@ -70,6 +69,7 @@ use sp_runtime::{ }; use sp_std::{cmp::Ordering, prelude::*}; use sp_version::RuntimeVersion; +use xcm::{IntoVersion, VersionedAssets, VersionedLocation, VersionedXcm}; // XCM Imports use xcm::v3::{ @@ -77,11 +77,15 @@ use xcm::v3::{ Junctions::{Here, X3}, MultiLocation, }; -use xcm_config::{PriceForSiblingParachainDelivery, XcmOriginToTransactDispatchOrigin}; - #[cfg(not(feature = "runtime-benchmarks"))] use xcm_config::XcmConfig; +use xcm_config::{PriceForSiblingParachainDelivery, XcmOriginToTransactDispatchOrigin}; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; + // Polimec Shared Imports pub use pallet_parachain_staking; pub use shared_configuration::{ @@ -95,6 +99,7 @@ use sp_version::NativeVersion; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; +use xcm::VersionedAssetId; #[cfg(feature = "runtime-benchmarks")] mod benchmark_helpers; @@ -1083,6 +1088,7 @@ impl pallet_funding::Config for Runtime { } use polimec_common::{PLMC_DECIMALS, PLMC_FOREIGN_ID, USD_DECIMALS}; + parameter_types! { // Fee is defined as 1.5% of the usd_amount. Since fee is applied to the plmc amount, and that is always 5 times // less than the usd_amount (multiplier of 5), we multiply the 1.5 by 5 to get 7.5% @@ -1133,14 +1139,6 @@ ord_parameter_types! { pub const DispenserAdminAccount: AccountId = AccountId::from(hex_literal::hex!("d85a4f58eb7dba17bc436b16f394b242271237021f7880e1ccaf36cd9a616c99")); } -// #[test] -// fn ensure_admin_account_is_correct() { -// use frame_support::traits::SortedMembers; -// use sp_core::crypto::Ss58Codec; -// let acc = AccountId::from_ss58check("5BAimacvMnhBEoc2g7PaiuEhJwmMZejq6j1ZMCpDZMHGAogz").unwrap(); -// assert_eq!(acc, DispenserAdminAccount::sorted_members()[0]); -// } - impl pallet_dispenser::Config for Runtime { type AdminOrigin = EnsureSignedBy; type BlockNumberToBalance = ConvertInto; @@ -1164,6 +1162,7 @@ impl Convert for ConvertMultilocationToAssetId { MultiLocation { parents: 1, interior: Here } => 10, MultiLocation { parents: 1, interior: X3(Parachain(1000), PalletInstance(50), GeneralIndex(1337)) } => 1337, MultiLocation { parents: 1, interior: X3(Parachain(1000), PalletInstance(50), GeneralIndex(1984)) } => 1984, + // asset 0 should be invalid. _ => 0, } } @@ -1654,6 +1653,54 @@ impl_runtime_apis! { Default::default() } } + + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + let acceptable_assets = vec![ + xcm_config::HereLocation::get().into(), + xcm_config::DotLocation::get().into(), + xcm_config::UsdtLocation::get().into(), + xcm_config::UsdcLocation::get().into() + ]; + + PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + match xcm::v3::AssetId::try_from(asset) { + Ok(xcm::v3::AssetId::Concrete(multilocation)) if multilocation == MultiLocation::here() => { + // for native token + Ok(TransactionPayment::weight_to_fee(weight)) + }, + Ok(xcm::v3::AssetId::Concrete(multilocation)) => { + let native_fee = TransactionPayment::weight_to_fee(weight); + let converted_asset_id = ConvertMultilocationToAssetId::convert(multilocation); + PLMCToFundingAssetBalance::to_asset_balance(native_fee, converted_asset_id).map_err(|_| XcmPaymentApiError::AssetNotFound) + }, + _ => { + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_call::(origin, call) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_xcm::(origin_location, xcm) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/runtimes/polimec/src/xcm_config.rs b/runtimes/polimec/src/xcm_config.rs index 0f419d94c..351d6345a 100644 --- a/runtimes/polimec/src/xcm_config.rs +++ b/runtimes/polimec/src/xcm_config.rs @@ -53,12 +53,12 @@ const DOT_PER_MB_PROOF: u128 = 0_2_000_000_000; // 0.0000001 DOT per Megabyte of // USDT from Polkadot Asset Hub const USDT_PER_SECOND_EXECUTION: u128 = 1_000_000; // 1 USDT per second of execution time const USDT_PER_MB_PROOF: u128 = 1_000_000; // 1 USDT per Megabyte of proof size -const USDT_JUNCTION: &[Junction] = &[Parachain(1000), PalletInstance(50), GeneralIndex(1984)]; +pub const USDT_JUNCTION: &[Junction] = &[Parachain(1000), PalletInstance(50), GeneralIndex(1984)]; // USDC from Polkadot Asset Hub const USDC_PER_SECOND_EXECUTION: u128 = 1_000_000; // 1 USDC per second of execution time const USDC_PER_MB_PROOF: u128 = 1_000_000; // 1 USDC per Megabyte of proof size -const USDC_JUNCTION: &[Junction] = &[Parachain(1000), PalletInstance(50), GeneralIndex(1337)]; +pub const USDC_JUNCTION: &[Junction] = &[Parachain(1000), PalletInstance(50), GeneralIndex(1337)]; parameter_types! { pub const RelayLocation: Location = Location::parent(); diff --git a/scripts/zombienet/polimec-paseo-local.toml b/scripts/zombienet/polimec-paseo-local.toml index 4ba85965c..9fbe60c16 100644 --- a/scripts/zombienet/polimec-paseo-local.toml +++ b/scripts/zombienet/polimec-paseo-local.toml @@ -1,3 +1,4 @@ + [settings] timeout = 1000 provider = "native"