From 54272be0f0d47e6db6cb1d087ade49c6941c0a67 Mon Sep 17 00:00:00 2001 From: imstar15 Date: Wed, 12 Jul 2023 21:14:33 +0800 Subject: [PATCH] Fix xcmp_fee for automation-time (#366) * Add asset_location param to get_local_currency_instructions function * Add Convert> to automationTime * Deduct fees based on different currency ID * Split DestinationAssetConfig into TransactInfoWithWeightLimit and DestinationAssetFeePerSecond * Change the type of destination to VersionedMultiLocation * Modify Mangata asset config * Customize XCMP fee and weight. * Fix typo * Calculate xcmp fee for alternate flow * Remove xcmp fee and weight calculation * Fix benchmark and tests * Fixing failed tests * Add migration * Code format * Fix schedule_xcmp_task_full test * Remove TransactInfo storage * Rename XcmFlow to XcmTaskSupported * Remove pallet_xcmp_handler storage in runtime configuration * Rename enum XcmTaskSupported to InstructionSequence * Change scheduleFee to MultiLcation * Fix the comment of AssetPayment * Extract instruction weight and fee to const variable in update_xcmp_task.rs * Fix tests for the merged code * Add calculate_schedule_fee_amount_works test * Add calculate_schedule_fee_amount tests * fixup: auto format Rust code * Add tests for all types of automation-time action * Set num_of_execution to a random number * Add comment for schedule_xcmp_task , schedule_xcmp_task_through_proxy function --------- Co-authored-by: oak-code-formatter --- Cargo.lock | 3 + node/src/chain_spec/neumann.rs | 9 +- node/src/chain_spec/oak.rs | 9 +- node/src/chain_spec/turing.rs | 53 +-- pallets/automation-time/Cargo.toml | 5 +- .../rpc/runtime-api/src/lib.rs | 2 +- pallets/automation-time/rpc/src/lib.rs | 2 +- pallets/automation-time/src/benchmarking.rs | 27 +- pallets/automation-time/src/fees.rs | 70 ++-- pallets/automation-time/src/lib.rs | 182 +++++--- pallets/automation-time/src/migrations/mod.rs | 2 + .../src/migrations/update_xcmp_task.rs | 225 ++++++++++ pallets/automation-time/src/mock.rs | 110 +++-- pallets/automation-time/src/tests.rs | 395 ++++++++++++++++-- pallets/automation-time/src/types.rs | 84 ++-- pallets/automation-time/src/weights.rs | 8 +- pallets/xcmp-handler/Cargo.toml | 4 + pallets/xcmp-handler/src/benchmarking.rs | 52 --- pallets/xcmp-handler/src/lib.rs | 374 ++++------------- pallets/xcmp-handler/src/mock.rs | 16 +- pallets/xcmp-handler/src/tests.rs | 302 ++----------- pallets/xcmp-handler/src/weights.rs | 98 ----- runtime/neumann/Cargo.toml | 1 - runtime/neumann/src/lib.rs | 35 +- runtime/neumann/src/xcm_config.rs | 6 +- runtime/oak/Cargo.toml | 1 - runtime/oak/src/lib.rs | 35 +- runtime/oak/src/xcm_config.rs | 8 +- runtime/turing/Cargo.toml | 1 - runtime/turing/src/lib.rs | 39 +- runtime/turing/src/xcm_config.rs | 8 +- 31 files changed, 1138 insertions(+), 1028 deletions(-) create mode 100644 pallets/automation-time/src/migrations/update_xcmp_task.rs delete mode 100644 pallets/xcmp-handler/src/benchmarking.rs delete mode 100644 pallets/xcmp-handler/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 0a641d4ff..46984795f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5949,9 +5949,11 @@ dependencies = [ "pallet-valve", "pallet-xcm", "pallet-xcmp-handler", + "parachain-info", "parity-scale-codec", "polkadot-parachain", "primitives", + "rand 0.7.3", "scale-info", "serde", "sp-core 7.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", @@ -6952,6 +6954,7 @@ dependencies = [ "frame-support 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", "frame-system 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", "log", + "orml-traits", "pallet-balances", "pallet-xcm", "parachain-info", diff --git a/node/src/chain_spec/neumann.rs b/node/src/chain_spec/neumann.rs index 2d5e78350..46f6503ab 100644 --- a/node/src/chain_spec/neumann.rs +++ b/node/src/chain_spec/neumann.rs @@ -2,7 +2,6 @@ use hex_literal::hex; use std::time::SystemTime; use cumulus_primitives_core::ParaId; -use frame_support::pallet_prelude::*; use sc_service::ChainType; use sc_telemetry::TelemetryEndpoints; use sp_core::{crypto::UncheckedInto, sr25519}; @@ -16,9 +15,8 @@ use crate::chain_spec::{ use common_runtime::constants::currency::{DOLLAR, TOKEN_DECIMALS}; use neumann_runtime::{ CouncilConfig, PolkadotXcmConfig, SudoConfig, TechnicalMembershipConfig, ValveConfig, - VestingConfig, XcmpHandlerConfig, + VestingConfig, }; -use pallet_xcmp_handler::XcmFlow; use primitives::{AccountId, AuraId, Balance}; static TOKEN_SYMBOL: &str = "NEU"; @@ -94,7 +92,6 @@ pub fn development_config() -> ChainSpec { get_account_id_from_seed::("Eve"), get_account_id_from_seed::("Ferdie"), ], - vec![], ) }, Vec::new(), @@ -186,7 +183,6 @@ pub fn local_testnet_config() -> ChainSpec { get_account_id_from_seed::("Eve"), get_account_id_from_seed::("Ferdie"), ], - vec![], ) }, // Bootnodes @@ -275,7 +271,6 @@ pub fn neumann_staging_testnet_config() -> ChainSpec { // 669ocRxey7vxUJs1TTRWe31zwrpGr8B13zRfAHB6yhhfcMud hex!["001fbcefa8c96f3d2e236688da5485a0af67988b78d61ea952f461255d1f4267"].into(), ], - vec![], ) }, // Bootnodes @@ -309,7 +304,6 @@ fn testnet_genesis( vesting_schedule: Vec<(u64, Vec<(AccountId, Balance)>)>, general_councils: Vec, technical_memberships: Vec, - xcmp_handler_asset_data: Vec<(Vec, u128, Weight, XcmFlow)>, ) -> neumann_runtime::GenesisConfig { neumann_runtime::GenesisConfig { system: neumann_runtime::SystemConfig { @@ -363,7 +357,6 @@ fn testnet_genesis( treasury: Default::default(), valve: ValveConfig { start_with_valve_closed: false, closed_gates: pallet_gates_closed }, vesting: VestingConfig { vesting_schedule }, - xcmp_handler: XcmpHandlerConfig { asset_data: xcmp_handler_asset_data }, asset_registry: Default::default(), } } diff --git a/node/src/chain_spec/oak.rs b/node/src/chain_spec/oak.rs index 00f2bcac0..e590e9590 100644 --- a/node/src/chain_spec/oak.rs +++ b/node/src/chain_spec/oak.rs @@ -1,7 +1,6 @@ use hex_literal::hex; use cumulus_primitives_core::ParaId; -use frame_support::pallet_prelude::*; use sc_service::ChainType; use sc_telemetry::TelemetryEndpoints; use sp_core::{crypto::UncheckedInto, sr25519}; @@ -16,9 +15,8 @@ use crate::chain_spec::{ use common_runtime::constants::currency::{DOLLAR, EXISTENTIAL_DEPOSIT, TOKEN_DECIMALS}; use oak_runtime::{ CouncilConfig, PolkadotXcmConfig, SudoConfig, TechnicalMembershipConfig, ValveConfig, - VestingConfig, XcmpHandlerConfig, + VestingConfig, }; -use pallet_xcmp_handler::XcmFlow; use primitives::{AccountId, AuraId, Balance}; const TOKEN_SYMBOL: &str = "OAK"; @@ -88,7 +86,6 @@ pub fn oak_development_config() -> ChainSpec { vec![], vec![get_account_id_from_seed::("Alice")], vec![get_account_id_from_seed::("Alice")], - vec![], ) }, Vec::new(), @@ -184,7 +181,6 @@ pub fn oak_staging() -> ChainSpec { // 5C571x5GLRQwfA3aRtVcxZzD7JnzNb3JbtZEvJWfQozWE54K hex!["004df6aeb14c73ef5cd2c57d9028afc402c4f101a8917bbb6cd19407c8bf8307"].into(), ], - vec![], ) }, // Bootnodes @@ -317,7 +313,6 @@ pub fn oak_live() -> ChainSpec { // 67nmVh57G9yo7sqiGLjgNNqtUd7H2CSESTyQgp5272aMibwS hex!["488ced7d199b4386081a52505962128da5a3f54f4665db3d78b6e9f9e89eea4d"].into(), ], - vec![], ) }, // Bootnodes @@ -347,7 +342,6 @@ fn testnet_genesis( vesting_schedule: Vec<(u64, Vec<(AccountId, Balance)>)>, general_councils: Vec, technical_memberships: Vec, - xcmp_handler_asset_data: Vec<(Vec, u128, Weight, XcmFlow)>, ) -> oak_runtime::GenesisConfig { let candidate_stake = std::cmp::max(oak_runtime::MinCollatorStk::get(), oak_runtime::MinCandidateStk::get()); @@ -403,7 +397,6 @@ fn testnet_genesis( treasury: Default::default(), valve: ValveConfig { start_with_valve_closed: false, closed_gates: pallet_gates_closed }, vesting: VestingConfig { vesting_schedule }, - xcmp_handler: XcmpHandlerConfig { asset_data: xcmp_handler_asset_data }, asset_registry: Default::default(), } } diff --git a/node/src/chain_spec/turing.rs b/node/src/chain_spec/turing.rs index 99db3f84d..113ab650a 100644 --- a/node/src/chain_spec/turing.rs +++ b/node/src/chain_spec/turing.rs @@ -1,5 +1,4 @@ use cumulus_primitives_core::ParaId; -use frame_support::pallet_prelude::*; use sc_service::ChainType; use sp_core::sr25519; use sp_runtime::{Perbill, Percent}; @@ -10,13 +9,12 @@ use crate::chain_spec::{ }; use codec::Encode; use common_runtime::constants::currency::{DOLLAR, TOKEN_DECIMALS}; -use pallet_xcmp_handler::XcmFlow; use primitives::{assets::CustomMetadata, AccountId, AuraId, Balance, TokenId}; use turing_runtime::{ AssetRegistryConfig, CouncilConfig, PolkadotXcmConfig, TechnicalMembershipConfig, ValveConfig, - VestingConfig, XcmpHandlerConfig, + VestingConfig, }; -use xcm::{prelude::*, VersionedMultiLocation, VersionedMultiLocation::V3}; +use xcm::{prelude::*, VersionedMultiLocation::V3}; const TOKEN_SYMBOL: &str = "TUR"; const SS_58_FORMAT: u32 = 51; @@ -84,40 +82,6 @@ pub fn turing_development_config() -> ChainSpec { get_account_id_from_seed::("Alice"), get_account_id_from_seed::("Bob"), ], - vec![ - ( - ::encode( - &(MultiLocation::new(1, X1(Parachain(1999))).into()), - ), - 419_000_000_000, - Weight::from_ref_time(1_000_000_000), - XcmFlow::Normal, - ), - ( - ::encode( - &(MultiLocation::new(1, X1(Parachain(2110))).into()), - ), - 419_000_000_000, - Weight::from_ref_time(1_000_000_000), - XcmFlow::Normal, - ), - ( - ::encode( - &(MultiLocation::new(1, X1(Parachain(2000))).into()), - ), - 10_000_000_000_000_000_000, - Weight::from_parts(1_000_000_000, 1024), - XcmFlow::Alternate, - ), - ( - ::encode( - &(MultiLocation::new(1, X2(Parachain(1000), PalletInstance(3))).into()), - ), - 10_000_000_000_000_000_000, - Weight::from_ref_time(250_000_000), - XcmFlow::Alternate, - ), - ], vec![ ( 1, @@ -127,7 +91,16 @@ pub fn turing_development_config() -> ChainSpec { name: b"Mangata Rococo".to_vec(), symbol: b"MGR".to_vec(), existential_deposit: Default::default(), - location: Some(MultiLocation::new(1, X1(Parachain(2110))).into()), + location: Some( + MultiLocation::new( + 1, + X2( + Parachain(2110), + GeneralKey { length: 4, data: [0; 32] }, + ), + ) + .into(), + ), additional: CustomMetadata { fee_per_second: Some(416_000_000_000), conversion_rate: None, @@ -234,7 +207,6 @@ fn testnet_genesis( vesting_schedule: Vec<(u64, Vec<(AccountId, Balance)>)>, general_councils: Vec, technical_memberships: Vec, - xcmp_handler_asset_data: Vec<(Vec, u128, Weight, XcmFlow)>, additional_assets: Vec<(TokenId, Vec)>, ) -> turing_runtime::GenesisConfig { let candidate_stake = std::cmp::max( @@ -316,7 +288,6 @@ fn testnet_genesis( treasury: Default::default(), valve: ValveConfig { start_with_valve_closed: false, closed_gates: pallet_gates_closed }, vesting: VestingConfig { vesting_schedule }, - xcmp_handler: XcmpHandlerConfig { asset_data: xcmp_handler_asset_data }, asset_registry: AssetRegistryConfig { assets, last_asset_id }, } } diff --git a/pallets/automation-time/Cargo.toml b/pallets/automation-time/Cargo.toml index aff12d651..f42e239b1 100644 --- a/pallets/automation-time/Cargo.toml +++ b/pallets/automation-time/Cargo.toml @@ -59,6 +59,7 @@ pallet-xcmp-handler = { path = "../xcmp-handler", default-features = false } primitives = { path = "../../primitives", default-features = false } [dev-dependencies] +rand = { version = "0.7.3" } serde = { version = "1.0.144" } sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } @@ -67,6 +68,9 @@ pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "p pallet-xcm = { git = 'https://github.com/paritytech/polkadot', default-features = false, branch = "release-v0.9.38" } xcm-executor = { git = 'https://github.com/paritytech/polkadot', default-features = false, branch = "release-v0.9.38" } +# Cumulus dependencies +parachain-info = { git = 'https://github.com/paritytech/cumulus', branch = 'polkadot-v0.9.38' } + orml-currencies = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } @@ -75,7 +79,6 @@ default = ["std"] runtime-benchmarks = [ "frame-benchmarking", "pallet-parachain-staking/runtime-benchmarks", - "pallet-xcmp-handler/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] std = [ diff --git a/pallets/automation-time/rpc/runtime-api/src/lib.rs b/pallets/automation-time/rpc/runtime-api/src/lib.rs index bab0e32c4..acd8e9a2d 100644 --- a/pallets/automation-time/rpc/runtime-api/src/lib.rs +++ b/pallets/automation-time/rpc/runtime-api/src/lib.rs @@ -45,8 +45,8 @@ pub enum AutomationAction { #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub struct FeeDetails { + pub schedule_fee: Balance, pub execution_fee: Balance, - pub xcmp_fee: Balance, } sp_api::decl_runtime_apis! { diff --git a/pallets/automation-time/rpc/src/lib.rs b/pallets/automation-time/rpc/src/lib.rs index a3078b47b..abc4e9e97 100644 --- a/pallets/automation-time/rpc/src/lib.rs +++ b/pallets/automation-time/rpc/src/lib.rs @@ -178,8 +178,8 @@ where }; Ok(FeeDetails { + schedule_fee: try_into_rpc_balance(fee_details.schedule_fee)?, execution_fee: try_into_rpc_balance(fee_details.execution_fee)?, - xcmp_fee: try_into_rpc_balance(fee_details.xcmp_fee)?, }) } diff --git a/pallets/automation-time/src/benchmarking.rs b/pallets/automation-time/src/benchmarking.rs index a56a92fd4..46e04fb55 100644 --- a/pallets/automation-time/src/benchmarking.rs +++ b/pallets/automation-time/src/benchmarking.rs @@ -81,11 +81,16 @@ fn schedule_xcmp_tasks(owner: T::AccountId, times: Vec, count: u owner.clone(), provided_id.clone(), times.clone(), - para_id.clone().try_into().unwrap(), - T::GetNativeCurrencyId::get(), - MultiLocation::new(1, X1(Parachain(para_id))).into(), + MultiLocation::new(1, X1(Parachain(para_id))), + MultiLocation::default(), + AssetPayment { + asset_location: MultiLocation::new(1, X1(Parachain(para_id))).into(), + amount: 0, + }, vec![4, 5, 6], Weight::from_ref_time(5_000), + Weight::from_ref_time(10_000), + InstructionSequence::PayThroughSovereignAccount, ) .unwrap(); let task_id = AutomationTime::::schedule_task(&task, provided_id.clone()).unwrap(); @@ -159,8 +164,11 @@ benchmarks! { } let schedule = ScheduleParam::Fixed { execution_times: times.clone() }; - let asset_location = MultiLocation::new(1, X1(Parachain(para_id))); - T::XcmpTransactor::setup_chain_asset_data(asset_location.clone())?; + let destination = MultiLocation::new(1, X1(Parachain(para_id))); + + let schedule_fee = T::CurrencyIdConvert::convert(currency_id).expect("IncoveribleCurrencyId"); + + let fee = AssetPayment { asset_location: MultiLocation::new(0, Here).into(), amount: 100u128 }; let mut provided_id = schedule_xcmp_tasks::(caller.clone(), times, max_tasks_per_slot - 1); provided_id = increment_provided_id(provided_id); @@ -169,7 +177,7 @@ benchmarks! { .saturating_mul(ED_MULTIPLIER.into()) .saturating_mul(DEPOSIT_MULTIPLIER.into()); let _ = T::MultiCurrency::deposit(currency_id.into(), &caller, foreign_currency_amount); - }: schedule_xcmp_task(RawOrigin::Signed(caller), provided_id, schedule, para_id.into(), currency_id, asset_location.into(), call, Weight::from_ref_time(1_000)) + }: schedule_xcmp_task(RawOrigin::Signed(caller), provided_id, schedule, Box::new(destination.into()), Box::new(schedule_fee.into()), Box::new(fee), call, Weight::from_ref_time(1_000), Weight::from_ref_time(2_000)) schedule_auto_compound_delegated_stake_task_full { let task_weight = ::WeightInfo::run_auto_compound_delegated_stake_task().ref_time(); @@ -279,24 +287,23 @@ benchmarks! { run_xcmp_task { let caller: T::AccountId = account("caller", 0, SEED); - let currency_id: T::CurrencyId = T::GetNativeCurrencyId::get(); let time: u64 = 10800; let para_id: u32 = 2001; let call = vec![4,5,6]; let local_para_id: u32 = 2114; + let destination = MultiLocation::new(1, X1(Parachain(para_id))); let local_sovereign_account: T::AccountId = Sibling::from(local_para_id).into_account_truncating(); T::Currency::deposit_creating( &local_sovereign_account, T::Currency::minimum_balance().saturating_mul(DEPOSIT_MULTIPLIER.into()), ); - let asset_location = MultiLocation::new(1, X1(Parachain(para_id))); - T::XcmpTransactor::setup_chain_asset_data(asset_location.clone())?; + let fee = AssetPayment { asset_location: MultiLocation::new(1, X1(Parachain(para_id))).into(), amount: 1000u128 }; let provided_id = schedule_xcmp_tasks::(caller.clone(), vec![time], 1); let task_id = Pallet::::generate_task_id(caller.clone(), provided_id); - }: { AutomationTime::::run_xcmp_task(para_id.clone().into(), caller, asset_location.into(), call, Weight::from_ref_time(100_000), task_id.clone()) } + }: { AutomationTime::::run_xcmp_task(destination, caller, fee, call, Weight::from_ref_time(100_000), Weight::from_ref_time(200_000), task_id.clone(), InstructionSequence::PayThroughSovereignAccount) } run_auto_compound_delegated_stake_task { let delegator: T::AccountId = account("delegator", 0, SEED); diff --git a/pallets/automation-time/src/fees.rs b/pallets/automation-time/src/fees.rs index 30b604b5c..2a2df488b 100644 --- a/pallets/automation-time/src/fees.rs +++ b/pallets/automation-time/src/fees.rs @@ -16,10 +16,10 @@ // limitations under the License. /// ! Traits and default implementation for paying execution fees. -use crate::{AccountOf, Action, ActionOf, Config, Error, MultiBalanceOf, MultiCurrencyId, Pallet}; +use crate::{AccountOf, Action, ActionOf, Config, Error, MultiBalanceOf, Pallet}; use orml_traits::MultiCurrency; -use pallet_xcmp_handler::XcmpTransactor; +use pallet_xcmp_handler::{InstructionSequence, XcmpTransactor}; use sp_runtime::{ traits::{CheckedSub, Convert, Saturating, Zero}, DispatchError, DispatchResult, SaturatedConversion, @@ -41,9 +41,9 @@ pub trait HandleFees { pub struct FeeHandler { owner: T::AccountId, - pub currency_id: MultiCurrencyId, - pub execution_fee: MultiBalanceOf, - pub xcmp_fee: MultiBalanceOf, + pub schedule_fee_location: MultiLocation, + pub schedule_fee_amount: MultiBalanceOf, + pub execution_fee_amount: MultiBalanceOf, _phantom_data: PhantomData, } @@ -73,46 +73,50 @@ where { /// Ensure the fee can be paid. fn can_pay_fee(&self) -> Result<(), DispatchError> { - let fee = self.execution_fee.saturating_add(self.xcmp_fee); + let fee = self.schedule_fee_amount.saturating_add(self.execution_fee_amount); if fee.is_zero() { return Ok(()) } // Manually check for ExistenceRequirement since MultiCurrency doesn't currently support it - let free_balance = T::MultiCurrency::free_balance(self.currency_id, &self.owner); + let currency_id = T::CurrencyIdConvert::convert(self.schedule_fee_location) + .ok_or("IncoveribleMultilocation")?; + let currency_id = currency_id.into(); + let free_balance = T::MultiCurrency::free_balance(currency_id, &self.owner); free_balance .checked_sub(&fee) .ok_or(DispatchError::Token(BelowMinimum))? - .checked_sub(&T::MultiCurrency::minimum_balance(self.currency_id)) + .checked_sub(&T::MultiCurrency::minimum_balance(currency_id)) .ok_or(DispatchError::Token(BelowMinimum))?; - T::MultiCurrency::ensure_can_withdraw(self.currency_id.into(), &self.owner, fee)?; + T::MultiCurrency::ensure_can_withdraw(currency_id, &self.owner, fee)?; Ok(()) } /// Withdraw the fee. fn withdraw_fee(&self) -> Result<(), DispatchError> { - let fee = self.execution_fee.saturating_add(self.xcmp_fee); + let fee = self.schedule_fee_amount.saturating_add(self.execution_fee_amount); if fee.is_zero() { return Ok(()) } - match T::MultiCurrency::withdraw(self.currency_id, &self.owner, fee) { + let currency_id = T::CurrencyIdConvert::convert(self.schedule_fee_location) + .ok_or("IncoveribleMultilocation")?; + let currency_id = currency_id.into(); + + match T::MultiCurrency::withdraw(currency_id, &self.owner, fee) { Ok(_) => { TR::take_revenue(MultiAsset { - id: AssetId::Concrete( - T::CurrencyIdConvert::convert(self.currency_id.into()) - .ok_or("IncoveribleCurrencyId")?, - ), - fun: Fungibility::Fungible(self.execution_fee.saturated_into()), + id: AssetId::Concrete(self.schedule_fee_location), + fun: Fungibility::Fungible(self.schedule_fee_amount.saturated_into()), }); - if self.xcmp_fee > MultiBalanceOf::::zero() { + if self.execution_fee_amount > MultiBalanceOf::::zero() { T::XcmpTransactor::pay_xcm_fee( self.owner.clone(), - self.xcmp_fee.saturated_into(), + self.execution_fee_amount.saturated_into(), )?; } @@ -128,29 +132,23 @@ where action: &ActionOf, executions: u32, ) -> Result { - let currency_id = action.currency_id::().into(); - - let execution_fee: u128 = - Pallet::::calculate_execution_fee(action, executions)?.saturated_into(); - - let xcmp_fee = match action.clone() { - Action::XCMP { para_id, xcm_asset_location, encoded_call_weight, .. } => - T::XcmpTransactor::get_xcm_fee( - u32::from(para_id), - MultiLocation::try_from(xcm_asset_location) - .map_err(|()| Error::::BadVersion)?, - encoded_call_weight.clone(), - )? - .saturating_mul(executions.into()) - .saturated_into(), + let schedule_fee_location = action.schedule_fee_location::().into(); + + let schedule_fee_amount: u128 = + Pallet::::calculate_schedule_fee_amount(action, executions)?.saturated_into(); + + let execution_fee_amount = match action.clone() { + Action::XCMP { execution_fee, instruction_sequence, .. } + if instruction_sequence == InstructionSequence::PayThroughSovereignAccount => + execution_fee.amount.saturating_mul(executions.into()).saturated_into(), _ => 0u32.saturated_into(), }; Ok(Self { owner: owner.clone(), - currency_id, - execution_fee: execution_fee.saturated_into(), - xcmp_fee, + schedule_fee_location, + schedule_fee_amount: schedule_fee_amount.saturated_into(), + execution_fee_amount, _phantom_data: Default::default(), }) } diff --git a/pallets/automation-time/src/lib.rs b/pallets/automation-time/src/lib.rs index bde723d65..2d91f7a56 100644 --- a/pallets/automation-time/src/lib.rs +++ b/pallets/automation-time/src/lib.rs @@ -67,6 +67,7 @@ use frame_system::pallet_prelude::*; use orml_traits::{FixedConversionRateProvider, MultiCurrency}; use pallet_parachain_staking::DelegatorActions; use pallet_timestamp::{self as timestamp}; +pub use pallet_xcmp_handler::InstructionSequence; use pallet_xcmp_handler::XcmpTransactor; use primitives::EnsureProxy; use scale_info::TypeInfo; @@ -90,8 +91,8 @@ pub mod pallet { >>::Balance; pub type TaskId = ::Hash; pub type AccountTaskId = (AccountOf, TaskId); - pub type ActionOf = Action, BalanceOf, ::CurrencyId>; - pub type TaskOf = Task, BalanceOf, ::CurrencyId>; + pub type ActionOf = Action, BalanceOf>; + pub type TaskOf = Task, BalanceOf>; pub type MissedTaskV2Of = MissedTaskV2, TaskId>; pub type ScheduledTasksOf = ScheduledTasks, TaskId>; pub type MultiCurrencyId = <::MultiCurrency as MultiCurrency< @@ -158,15 +159,12 @@ pub mod pallet { type XcmpTransactor: XcmpTransactor; /// Converts CurrencyId to Multiloc - type CurrencyIdConvert: Convert>; + type CurrencyIdConvert: Convert> + + Convert>; /// Converts between comparable currencies type FeeConversionRateProvider: FixedConversionRateProvider; - /// The currencyId for the native currency. - #[pallet::constant] - type GetNativeCurrencyId: Get; - /// Handler for fees type FeeHandler: HandleFees; @@ -184,6 +182,12 @@ pub mod pallet { /// Ensure proxy type EnsureProxy: primitives::EnsureProxy; + + /// This chain's Universal Location. + type UniversalLocation: Get; + + //The paraId of this chain. + type SelfParaId: Get; } #[pallet::pallet] @@ -258,6 +262,8 @@ pub mod pallet { /// The version of the `VersionedMultiLocation` value used is not able /// to be interpreted. BadVersion, + UnsupportedFeePayment, + CannotReanchor, } #[pallet::event] @@ -290,12 +296,12 @@ pub mod pallet { /// Successfully sent XCMP XcmpTaskSucceeded { task_id: T::Hash, - para_id: ParaId, + destination: MultiLocation, }, /// Failed to send XCMP XcmpTaskFailed { task_id: T::Hash, - para_id: ParaId, + destination: MultiLocation, error: DispatchError, }, /// Transfer Failed @@ -376,11 +382,13 @@ pub mod pallet { /// /// # Parameters /// * `provided_id`: An id provided by the user. This id must be unique for the user. - /// * `execution_times`: The list of unix standard times in seconds for when the task should run. - /// * `para_id`: Parachain id the XCMP call will be sent to. - /// * `currency_id`: The currency in which fees will be paid. + /// * `schedule`: The triggering rules for recurring task or the list of unix standard times in seconds for when the task should run. + /// * `destination`: Destination the XCMP call will be sent to. + /// * `schedule_fee`: The payment asset location required for scheduling automation task. + /// * `execution_fee`: The fee will be paid for XCMP execution. /// * `encoded_call`: Call that will be sent via XCMP to the parachain id provided. /// * `encoded_call_weight`: Required weight at most the provided call will take. + /// * `overall_weight`: The overall weight in which fees will be paid for XCM instructions. /// /// # Errors /// * `InvalidTime`: Time must end in a whole hour. @@ -388,26 +396,34 @@ pub mod pallet { /// * `DuplicateTask`: There can be no duplicate tasks. /// * `TimeTooFarOut`: Execution time or frequency are past the max time horizon. /// * `TimeSlotFull`: Time slot is full. No more tasks can be scheduled for this time. + /// * `UnsupportedFeePayment`: Time slot is full. No more tasks can be scheduled for this time. #[pallet::call_index(2)] #[pallet::weight(::WeightInfo::schedule_xcmp_task_full(schedule.number_of_executions()))] pub fn schedule_xcmp_task( origin: OriginFor, provided_id: Vec, schedule: ScheduleParam, - para_id: ParaId, - currency_id: T::CurrencyId, - xcm_asset_location: VersionedMultiLocation, + destination: Box, + schedule_fee: Box, + execution_fee: Box, encoded_call: Vec, encoded_call_weight: Weight, + overall_weight: Weight, ) -> DispatchResult { let who = ensure_signed(origin)?; + let destination = + MultiLocation::try_from(*destination).map_err(|()| Error::::BadVersion)?; + let schedule_fee = + MultiLocation::try_from(*schedule_fee).map_err(|()| Error::::BadVersion)?; let action = Action::XCMP { - para_id, - currency_id, - xcm_asset_location, + destination, + schedule_fee, + execution_fee: *execution_fee, encoded_call, encoded_call_weight, + overall_weight, schedule_as: None, + instruction_sequence: InstructionSequence::PayThroughSovereignAccount, }; let schedule = schedule.validated_into::()?; @@ -416,17 +432,44 @@ pub mod pallet { Ok(().into()) } + /// Schedule a task through XCMP through proxy account to fire an XCMP message with a provided call. + /// + /// Before the task can be scheduled the task must past validation checks. + /// * The transaction is signed + /// * The provided_id's length > 0 + /// * The times are valid + /// * The given asset location is supported + /// + /// # Parameters + /// * `provided_id`: An id provided by the user. This id must be unique for the user. + /// * `schedule`: The triggering rules for recurring task or the list of unix standard times in seconds for when the task should run. + /// * `destination`: Destination the XCMP call will be sent to. + /// * `schedule_fee`: The payment asset location required for scheduling automation task. + /// * `execution_fee`: The fee will be paid for XCMP execution. + /// * `encoded_call`: Call that will be sent via XCMP to the parachain id provided. + /// * `encoded_call_weight`: Required weight at most the provided call will take. + /// * `overall_weight`: The overall weight in which fees will be paid for XCM instructions. + /// + /// # Errors + /// * `InvalidTime`: Time must end in a whole hour. + /// * `PastTime`: Time must be in the future. + /// * `DuplicateTask`: There can be no duplicate tasks. + /// * `TimeTooFarOut`: Execution time or frequency are past the max time horizon. + /// * `TimeSlotFull`: Time slot is full. No more tasks can be scheduled for this time. + /// * `UnsupportedFeePayment`: Time slot is full. No more tasks can be scheduled for this time. + /// * `Other("proxy error: expected `ProxyType::Any`")`: schedule_as must be a proxy account of type "any" for the caller. #[pallet::call_index(3)] #[pallet::weight(::WeightInfo::schedule_xcmp_task_full(schedule.number_of_executions()).saturating_add(T::DbWeight::get().reads(1)))] pub fn schedule_xcmp_task_through_proxy( origin: OriginFor, provided_id: Vec, schedule: ScheduleParam, - para_id: ParaId, - currency_id: T::CurrencyId, - xcm_asset_location: VersionedMultiLocation, + destination: Box, + schedule_fee: Box, + execution_fee: Box, encoded_call: Vec, encoded_call_weight: Weight, + overall_weight: Weight, schedule_as: T::AccountId, ) -> DispatchResult { let who = ensure_signed(origin)?; @@ -434,13 +477,20 @@ pub mod pallet { // Make sure the owner is the proxy account of the user account. T::EnsureProxy::ensure_ok(schedule_as.clone(), who.clone())?; + let destination = + MultiLocation::try_from(*destination).map_err(|()| Error::::BadVersion)?; + let schedule_fee = + MultiLocation::try_from(*schedule_fee).map_err(|()| Error::::BadVersion)?; + let action = Action::XCMP { - para_id, - currency_id, - xcm_asset_location, + destination, + schedule_fee, + execution_fee: *execution_fee, encoded_call, encoded_call_weight, + overall_weight, schedule_as: Some(schedule_as), + instruction_sequence: InstructionSequence::PayThroughRemoteDerivativeAccount, }; let schedule = schedule.validated_into::()?; @@ -860,19 +910,23 @@ pub mod pallet { Action::NativeTransfer { sender, recipient, amount } => Self::run_native_transfer_task(sender, recipient, amount, *task_id), Action::XCMP { - para_id, + destination, + execution_fee, schedule_as, - xcm_asset_location, encoded_call, encoded_call_weight, + overall_weight, + instruction_sequence, .. } => Self::run_xcmp_task( - para_id, + destination, schedule_as.unwrap_or(task.owner_id.clone()), - xcm_asset_location, + execution_fee, encoded_call, encoded_call_weight, + overall_weight, *task_id, + instruction_sequence, ), Action::AutoCompoundDelegatedStake { delegator, @@ -994,34 +1048,40 @@ pub mod pallet { } pub fn run_xcmp_task( - para_id: ParaId, + destination: MultiLocation, caller: T::AccountId, - xcm_asset_location: VersionedMultiLocation, + fee: AssetPayment, encoded_call: Vec, encoded_call_weight: Weight, + overall_weight: Weight, task_id: TaskId, + flow: InstructionSequence, ) -> (Weight, Option) { - let location = MultiLocation::try_from(xcm_asset_location); - if location.is_err() { + let fee_asset_location = MultiLocation::try_from(fee.asset_location); + if fee_asset_location.is_err() { return ( ::WeightInfo::run_xcmp_task(), Some(Error::::BadVersion.into()), ) } + let fee_asset_location = fee_asset_location.unwrap(); match T::XcmpTransactor::transact_xcm( - para_id.into(), - location.unwrap(), + destination, + fee_asset_location, + fee.amount, caller, encoded_call, encoded_call_weight, + overall_weight, + flow, ) { Ok(()) => { - Self::deposit_event(Event::XcmpTaskSucceeded { task_id, para_id }); + Self::deposit_event(Event::XcmpTaskSucceeded { task_id, destination }); (::WeightInfo::run_xcmp_task(), None) }, Err(e) => { - Self::deposit_event(Event::XcmpTaskFailed { task_id, para_id, error: e }); + Self::deposit_event(Event::XcmpTaskFailed { task_id, destination, error: e }); (::WeightInfo::run_xcmp_task(), Some(e)) }, } @@ -1037,7 +1097,7 @@ pub mod pallet { ) -> (Weight, Option) { // TODO: Handle edge case where user has enough funds to run task but not reschedule let reserved_funds = account_minimum - .saturating_add(Self::calculate_execution_fee(&task.action, 1).expect("Can only fail for DynamicDispatch and this is always AutoCompoundDelegatedStake")); + .saturating_add(Self::calculate_schedule_fee_amount(&task.action, 1).expect("Can only fail for DynamicDispatch and this is always AutoCompoundDelegatedStake")); match T::DelegatorActions::delegator_bond_till_minimum( &delegator, &collator, @@ -1289,6 +1349,27 @@ pub mod pallet { Err(Error::::EmptyProvidedId)? } + match action.clone() { + Action::XCMP { execution_fee, instruction_sequence, .. } => { + let asset_location = MultiLocation::try_from(execution_fee.asset_location) + .map_err(|()| Error::::BadVersion)?; + let asset_location = asset_location + .reanchored( + &MultiLocation::new(1, X1(Parachain(T::SelfParaId::get().into()))) + .into(), + T::UniversalLocation::get(), + ) + .map_err(|_| Error::::CannotReanchor)?; + // Only native token are supported as the XCMP fee for local deductions + if instruction_sequence == InstructionSequence::PayThroughSovereignAccount && + asset_location != MultiLocation::new(0, Here).into() + { + Err(Error::::UnsupportedFeePayment)? + } + }, + _ => (), + }; + let executions = schedule.known_executions_left(); let task = @@ -1413,23 +1494,30 @@ pub mod pallet { /// /// Fee saturates at Weight/BalanceOf when there are an unreasonable num of executions /// In practice, executions is bounded by T::MaxExecutionTimes and unlikely to saturate - pub fn calculate_execution_fee( + pub fn calculate_schedule_fee_amount( action: &ActionOf, executions: u32, ) -> Result, DispatchError> { let total_weight = action.execution_weight::()?.saturating_mul(executions.into()); - let currency_id = action.currency_id::(); - let fee = if currency_id == T::GetNativeCurrencyId::get() { + + let schedule_fee_location = action.schedule_fee_location::(); + let schedule_fee_location = schedule_fee_location + .reanchored( + &MultiLocation::new(1, X1(Parachain(T::SelfParaId::get().into()))).into(), + T::UniversalLocation::get(), + ) + .map_err(|_| Error::::CannotReanchor)?; + + let fee = if schedule_fee_location == MultiLocation::default() { T::ExecutionWeightFee::get() .saturating_mul(>::saturated_from(total_weight)) } else { - let loc = - T::CurrencyIdConvert::convert(currency_id).ok_or("IncoveribleCurrencyId")?; - let raw_fee = T::FeeConversionRateProvider::get_fee_per_second(&loc) - .ok_or("CouldNotDetermineFeePerSecond")? - .checked_mul(total_weight as u128) - .ok_or("FeeOverflow") - .map(|raw_fee| raw_fee / (WEIGHT_REF_TIME_PER_SECOND as u128))?; + let raw_fee = + T::FeeConversionRateProvider::get_fee_per_second(&schedule_fee_location) + .ok_or("CouldNotDetermineFeePerSecond")? + .checked_mul(total_weight as u128) + .ok_or("FeeOverflow") + .map(|raw_fee| raw_fee / (WEIGHT_REF_TIME_PER_SECOND as u128))?; >::saturated_from(raw_fee) }; diff --git a/pallets/automation-time/src/migrations/mod.rs b/pallets/automation-time/src/migrations/mod.rs index 168db000f..1a3fff88f 100644 --- a/pallets/automation-time/src/migrations/mod.rs +++ b/pallets/automation-time/src/migrations/mod.rs @@ -1 +1,3 @@ // Migrations + +pub mod update_xcmp_task; diff --git a/pallets/automation-time/src/migrations/update_xcmp_task.rs b/pallets/automation-time/src/migrations/update_xcmp_task.rs new file mode 100644 index 000000000..d5b1bddac --- /dev/null +++ b/pallets/automation-time/src/migrations/update_xcmp_task.rs @@ -0,0 +1,225 @@ +use core::marker::PhantomData; + +use crate::{ + weights::WeightInfo, AccountOf, ActionOf, AssetPayment, BalanceOf, Config, InstructionSequence, + Schedule, TaskId, TaskOf, +}; +use codec::{Decode, Encode}; +use cumulus_primitives_core::ParaId; +use frame_support::{traits::OnRuntimeUpgrade, weights::Weight, Twox64Concat}; +use scale_info::TypeInfo; +use sp_runtime::traits::Convert; +use sp_std::vec::Vec; +use xcm::{latest::prelude::*, VersionedMultiLocation}; + +const EXECUTION_FEE_AMOUNT: u128 = 3_000_000_000; +const INSTRUCTION_WEIGHT_REF_TIME: u64 = 150_000_000; + +#[derive(Debug, Encode, Decode, TypeInfo)] +#[scale_info(skip_type_params(MaxExecutionTimes))] +pub struct OldTask { + pub owner_id: T::AccountId, + pub provided_id: Vec, + pub schedule: Schedule, + pub action: OldAction, +} + +impl From> for TaskOf { + fn from(task: OldTask) -> Self { + TaskOf:: { + owner_id: task.owner_id, + provided_id: task.provided_id, + schedule: task.schedule, + action: task.action.into(), + } + } +} + +/// The enum that stores all action specific data. +#[derive(Clone, Debug, Eq, PartialEq, Encode, Decode, TypeInfo)] +pub enum OldAction { + Notify { + message: Vec, + }, + NativeTransfer { + sender: T::AccountId, + recipient: T::AccountId, + amount: BalanceOf, + }, + XCMP { + para_id: ParaId, + currency_id: T::CurrencyId, + xcm_asset_location: VersionedMultiLocation, + encoded_call: Vec, + encoded_call_weight: Weight, + schedule_as: Option, + }, + AutoCompoundDelegatedStake { + delegator: T::AccountId, + collator: T::AccountId, + account_minimum: BalanceOf, + }, + DynamicDispatch { + encoded_call: Vec, + }, +} + +impl From> for ActionOf { + fn from(action: OldAction) -> Self { + match action { + OldAction::AutoCompoundDelegatedStake { delegator, collator, account_minimum } => + Self::AutoCompoundDelegatedStake { delegator, collator, account_minimum }, + OldAction::Notify { message } => Self::Notify { message }, + OldAction::NativeTransfer { sender, recipient, amount } => + Self::NativeTransfer { sender, recipient, amount }, + OldAction::XCMP { + para_id, + currency_id, + encoded_call, + encoded_call_weight, + schedule_as, + .. + } => { + let schedule_fee = + T::CurrencyIdConvert::convert(currency_id).expect("IncoveribleCurrencyId"); + Self::XCMP { + destination: MultiLocation::new(1, X1(Parachain(para_id.into()))), + schedule_fee, + execution_fee: AssetPayment { + asset_location: MultiLocation::new(0, Here).into(), + amount: EXECUTION_FEE_AMOUNT, + }, + encoded_call, + encoded_call_weight: encoded_call_weight.clone(), + overall_weight: encoded_call_weight.saturating_add( + Weight::from_ref_time(INSTRUCTION_WEIGHT_REF_TIME).saturating_mul(6), + ), + schedule_as, + instruction_sequence: InstructionSequence::PayThroughSovereignAccount, + } + }, + OldAction::DynamicDispatch { encoded_call } => Self::DynamicDispatch { encoded_call }, + } + } +} + +#[frame_support::storage_alias] +pub type AccountTasks = StorageDoubleMap< + AutomationTime, + Twox64Concat, + AccountOf, + Twox64Concat, + TaskId, + OldTask, +>; + +pub struct UpdateXcmpTask(PhantomData); +impl OnRuntimeUpgrade for UpdateXcmpTask { + fn on_runtime_upgrade() -> Weight { + log::info!(target: "automation-time", "UpdateXcmpTask migration"); + + let mut migrated_tasks = 0u32; + AccountTasks::::iter().for_each(|(account_id, task_id, task)| { + let migrated_task: TaskOf = task.into(); + crate::AccountTasks::::insert(account_id, task_id, migrated_task); + + migrated_tasks += 1; + }); + + log::info!( + target: "automation-time", + "migration: UpdateXcmpTask succesful! Migrated {} tasks.", + migrated_tasks + ); + + ::WeightInfo::migration_upgrade_xcmp_task(migrated_tasks) + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + let prev_count = crate::AccountTasks::::iter().count() as u32; + Ok(prev_count.encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(prev_count: Vec) -> Result<(), &'static str> { + let prev_count: u32 = Decode::decode(&mut prev_count.as_slice()) + .expect("the state parameter should be something that was generated by pre_upgrade"); + let post_count = crate::AccountTasks::::iter().count() as u32; + assert!(post_count == prev_count); + + Ok(()) + } +} + +#[cfg(test)] +mod test { + use super::{ + OldAction, OldTask, ParaId, UpdateXcmpTask, EXECUTION_FEE_AMOUNT, + INSTRUCTION_WEIGHT_REF_TIME, + }; + use crate::{mock::*, ActionOf, AssetPayment, InstructionSequence, Pallet, Schedule, TaskOf}; + use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; + use sp_runtime::AccountId32; + use xcm::latest::prelude::*; + + #[test] + fn on_runtime_upgrade() { + new_test_ext(0).execute_with(|| { + let para_id: ParaId = 1000.into(); + let account_id = AccountId32::new(ALICE); + let schedule_as = Some(AccountId32::new(BOB)); + let task_id = Pallet::::generate_task_id(account_id.clone(), vec![1]); + let encoded_call_weight = Weight::from_ref_time(10); + + let task = OldTask:: { + owner_id: account_id.clone(), + provided_id: vec![1], + schedule: Schedule::Fixed { + execution_times: vec![0, 1].try_into().unwrap(), + executions_left: 2, + }, + action: OldAction::::XCMP { + para_id, + currency_id: 0u32.into(), + xcm_asset_location: MultiLocation::new(1, X1(Parachain(para_id.into()))).into(), + encoded_call: vec![0u8], + encoded_call_weight: encoded_call_weight.clone(), + schedule_as: schedule_as.clone(), + }, + }; + + super::AccountTasks::::insert(account_id.clone(), task_id, task); + + UpdateXcmpTask::::on_runtime_upgrade(); + + assert_eq!(crate::AccountTasks::::iter().count(), 1); + assert_eq!( + crate::AccountTasks::::get(account_id.clone(), task_id).unwrap(), + TaskOf:: { + owner_id: account_id.clone(), + provided_id: vec![1], + schedule: Schedule::Fixed { + execution_times: vec![0, 1].try_into().unwrap(), + executions_left: 2 + }, + action: ActionOf::::XCMP { + destination: MultiLocation::new(1, X1(Parachain(para_id.into()))), + schedule_fee: MultiLocation::default(), + execution_fee: AssetPayment { + asset_location: MultiLocation::new(0, Here).into(), + amount: EXECUTION_FEE_AMOUNT, + }, + encoded_call: vec![0u8], + encoded_call_weight: encoded_call_weight.clone(), + overall_weight: encoded_call_weight.saturating_add( + Weight::from_ref_time(INSTRUCTION_WEIGHT_REF_TIME).saturating_mul(6) + ), + schedule_as, + instruction_sequence: InstructionSequence::PayThroughSovereignAccount, + }, + } + ); + }) + } +} diff --git a/pallets/automation-time/src/mock.rs b/pallets/automation-time/src/mock.rs index 5808e7b5e..441d8d7b4 100644 --- a/pallets/automation-time/src/mock.rs +++ b/pallets/automation-time/src/mock.rs @@ -47,6 +47,37 @@ pub const PROXY_ACCOUNT: [u8; 32] = [4u8; 32]; pub const PARA_ID: u32 = 2000; pub const NATIVE: CurrencyId = 0; +pub const NATIVE_LOCATION: MultiLocation = MultiLocation { parents: 0, interior: Here }; +pub const NATIVE_EXECUTION_WEIGHT_FEE: u128 = 12; +pub const FOREIGN_CURRENCY_ID: CurrencyId = 1; + +pub const MOONBASE_ASSET_LOCATION: MultiLocation = + MultiLocation { parents: 1, interior: X2(Parachain(1000), PalletInstance(3)) }; +pub const UNKNOWN_SCHEDULE_FEE: MultiLocation = + MultiLocation { parents: 1, interior: X1(Parachain(4000)) }; + +pub struct MockAssetFeePerSecond { + pub asset_location: MultiLocation, + pub fee_per_second: u128, +} + +pub const ASSET_FEE_PER_SECOND: [MockAssetFeePerSecond; 3] = [ + MockAssetFeePerSecond { + asset_location: MultiLocation { parents: 1, interior: X1(Parachain(2000)) }, + fee_per_second: 416_000_000_000, + }, + MockAssetFeePerSecond { + asset_location: MultiLocation { + parents: 1, + interior: X2(Parachain(2110), GeneralKey { length: 4, data: [0; 32] }), + }, + fee_per_second: 416_000_000_000, + }, + MockAssetFeePerSecond { + asset_location: MOONBASE_ASSET_LOCATION, + fee_per_second: 10_000_000_000_000_000_000, + }, +]; construct_runtime!( pub enum Test where @@ -57,6 +88,7 @@ construct_runtime!( System: system::{Pallet, Call, Config, Storage, Event}, Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + ParachainInfo: parachain_info::{Pallet, Storage, Config}, Tokens: orml_tokens::{Pallet, Storage, Event, Config}, Currencies: orml_currencies::{Pallet, Call}, AutomationTime: pallet_automation_time::{Pallet, Call, Storage, Event}, @@ -113,6 +145,8 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; } +impl parachain_info::Config for Test {} + parameter_type_with_key! { pub ExistentialDeposits: |_currency_id: CurrencyId| -> Balance { Default::default() @@ -196,7 +230,7 @@ parameter_types! { pub const MaxBlockWeight: u64 = 1_000_000; pub const MaxWeightPercentage: Perbill = Perbill::from_percent(10); pub const UpdateQueueRatio: Perbill = Perbill::from_percent(50); - pub const ExecutionWeightFee: Balance = 12; + pub const ExecutionWeightFee: Balance = NATIVE_EXECUTION_WEIGHT_FEE; // When unit testing dynamic dispatch, we use the real weight value of the extrinsics call // This is an external lib that we don't own so we try to not mock, follow the rule don't mock @@ -314,7 +348,7 @@ impl pallet_automation_time::WeightInfo for MockWeig fn shift_missed_tasks() -> Weight { Weight::from_ref_time(900_000) } - fn migration_upgrade_weight_struct(_: u32) -> Weight { + fn migration_upgrade_xcmp_task(_: u32) -> Weight { Weight::zero() } } @@ -327,33 +361,21 @@ where C: frame_support::traits::ReservableCurrency, { fn transact_xcm( - _para_id: u32, + _destination: MultiLocation, _location: xcm::latest::MultiLocation, + _fee: u128, _caller: T::AccountId, _transact_encoded_call: sp_std::vec::Vec, _transact_encoded_call_weight: Weight, + _overall_weight: Weight, + _flow: InstructionSequence, ) -> Result<(), sp_runtime::DispatchError> { Ok(().into()) } - fn get_xcm_fee( - _para_id: u32, - _location: xcm::latest::MultiLocation, - _transact_encoded_call_weight: Weight, - ) -> Result { - Ok(XmpFee::get()) - } - fn pay_xcm_fee(_: T::AccountId, _: u128) -> Result<(), sp_runtime::DispatchError> { Ok(().into()) } - - #[cfg(feature = "runtime-benchmarks")] - fn setup_chain_asset_data( - _asset_location: xcm::latest::MultiLocation, - ) -> Result<(), sp_runtime::DispatchError> { - Ok(().into()) - } } pub struct ScheduleAllowList; @@ -369,8 +391,8 @@ impl Contains for ScheduleAllowList { pub struct MockConversionRateProvider; impl FixedConversionRateProvider for MockConversionRateProvider { - fn get_fee_per_second(_location: &MultiLocation) -> Option { - Some(1) + fn get_fee_per_second(location: &MultiLocation) -> Option { + get_fee_per_second(location) } } @@ -378,9 +400,21 @@ pub struct MockTokenIdConvert; impl Convert> for MockTokenIdConvert { fn convert(id: CurrencyId) -> Option { if id == NATIVE { - Some(MultiLocation::new(1, Here)) - } else if id == 1 { - Some(MultiLocation::new(1, X1(Parachain(2110)))) + Some(MultiLocation::new(0, Here)) + } else if id == FOREIGN_CURRENCY_ID { + Some(MultiLocation::new(1, X1(Parachain(PARA_ID)))) + } else { + None + } + } +} + +impl Convert> for MockTokenIdConvert { + fn convert(location: MultiLocation) -> Option { + if location == MultiLocation::new(0, Here) { + Some(NATIVE) + } else if location == MultiLocation::new(1, X1(Parachain(PARA_ID))) { + Some(FOREIGN_CURRENCY_ID) } else { None } @@ -398,6 +432,13 @@ impl EnsureProxy for MockEnsureProxy { } } +parameter_types! { + pub const RelayNetwork: NetworkId = NetworkId::Rococo; + // The universal location within the global consensus system + pub UniversalLocation: InteriorMultiLocation = + X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); +} + impl pallet_automation_time::Config for Test { type RuntimeEvent = RuntimeEvent; type MaxTasksPerSlot = MaxTasksPerSlot; @@ -415,12 +456,13 @@ impl pallet_automation_time::Config for Test { type FeeHandler = FeeHandler; type DelegatorActions = MockDelegatorActions; type XcmpTransactor = MockXcmpTransactor; - type GetNativeCurrencyId = GetNativeCurrencyId; type Call = RuntimeCall; type ScheduleAllowList = ScheduleAllowList; type CurrencyIdConvert = MockTokenIdConvert; type FeeConversionRateProvider = MockConversionRateProvider; type EnsureProxy = MockEnsureProxy; + type UniversalLocation = UniversalLocation; + type SelfParaId = parachain_info::Pallet; } // Build genesis storage according to the mock runtime. @@ -602,3 +644,23 @@ pub fn fund_account( u128::from(ExistentialDeposit::get()); _ = ::Currency::deposit_creating(account, amount); } + +pub fn get_fee_per_second(location: &MultiLocation) -> Option { + let location = location + .reanchored( + &MultiLocation::new(1, X1(Parachain(::SelfParaId::get().into()))) + .into(), + ::UniversalLocation::get(), + ) + .expect("Reanchor location failed"); + + let found_asset = ASSET_FEE_PER_SECOND.into_iter().find(|item| match item { + MockAssetFeePerSecond { asset_location, .. } => *asset_location == location, + }); + + if found_asset.is_some() { + Some(found_asset.unwrap().fee_per_second) + } else { + None + } +} diff --git a/pallets/automation-time/src/tests.rs b/pallets/automation-time/src/tests.rs index 53c53896e..eab7f9617 100644 --- a/pallets/automation-time/src/tests.rs +++ b/pallets/automation-time/src/tests.rs @@ -16,27 +16,111 @@ // limitations under the License. use crate::{ - mock::*, AccountTasks, Action, Config, Error, LastTimeSlot, MissedTaskV2Of, ScheduleParam, - ScheduledTasksOf, TaskHashInput, TaskOf, TaskQueueV2, WeightInfo, + mock::*, AccountTasks, Action, ActionOf, AssetPayment, Config, Error, InstructionSequence, + LastTimeSlot, MissedTaskV2Of, ScheduleParam, ScheduledTasksOf, TaskHashInput, TaskOf, + TaskQueueV2, WeightInfo, }; use codec::Encode; -use core::convert::TryInto; -use frame_support::{assert_noop, assert_ok, traits::OnInitialize, weights::Weight}; +use frame_support::{ + assert_noop, assert_ok, + dispatch::GetDispatchInfo, + traits::OnInitialize, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, +}; use frame_system::{self, RawOrigin}; -use pallet_balances; - -use pallet_valve::Shutdown; +use rand::Rng; +use sp_core::Get; use sp_runtime::{ traits::{BlakeTwo256, Hash}, AccountId32, }; +use xcm::latest::{prelude::*, Junction::Parachain, MultiLocation}; -use xcm::latest::{prelude::X1, Junction::Parachain, MultiLocation}; +use pallet_balances; +use pallet_valve::Shutdown; pub const START_BLOCK_TIME: u64 = 33198768000 * 1_000; pub const SCHEDULED_TIME: u64 = START_BLOCK_TIME / 1_000 + 7200; const LAST_BLOCK_TIME: u64 = START_BLOCK_TIME / 1_000; +const EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT: &str = "Calculate schedule fee amount should work"; + +const DEFAULT_SCHEDULE_FEE_LOCATION: MultiLocation = MOONBASE_ASSET_LOCATION; + +struct XcmpActionParams { + destination: MultiLocation, + schedule_fee: MultiLocation, + execution_fee: AssetPayment, + encoded_call: Vec, + encoded_call_weight: Weight, + overall_weight: Weight, + schedule_as: Option, + instruction_sequence: InstructionSequence, +} + +impl Default for XcmpActionParams { + fn default() -> Self { + let delegator_account = AccountId32::new(DELEGATOR_ACCOUNT); + XcmpActionParams { + destination: MultiLocation::new(1, X1(Parachain(PARA_ID))), + schedule_fee: DEFAULT_SCHEDULE_FEE_LOCATION.into(), + execution_fee: AssetPayment { + asset_location: MOONBASE_ASSET_LOCATION.into(), + amount: 100, + }, + encoded_call: vec![3, 4, 5], + encoded_call_weight: Weight::from_ref_time(100_000), + overall_weight: Weight::from_ref_time(200_000), + schedule_as: Some(delegator_account), + instruction_sequence: InstructionSequence::PayThroughRemoteDerivativeAccount, + } + } +} + +fn create_xcmp_action(options: XcmpActionParams) -> ActionOf { + Action::XCMP { + destination: options.destination, + schedule_fee: options.schedule_fee, + execution_fee: options.execution_fee, + encoded_call: options.encoded_call, + encoded_call_weight: options.encoded_call_weight, + overall_weight: options.overall_weight, + schedule_as: options.schedule_as, + instruction_sequence: options.instruction_sequence, + } +} + +fn generate_random_num(min: u32, max: u32) -> u32 { + rand::thread_rng().gen_range(min, max) +} + +fn calculate_local_action_schedule_fee(weight: Weight, num_of_execution: u32) -> u128 { + NATIVE_EXECUTION_WEIGHT_FEE * (weight.ref_time() as u128) * (num_of_execution as u128) +} + +fn calculate_expected_xcmp_action_schedule_fee( + schedule_fee_location: MultiLocation, + num_of_execution: u32, +) -> u128 { + let schedule_fee_location = schedule_fee_location + .reanchored( + &MultiLocation::new(1, X1(Parachain(::SelfParaId::get().into()))) + .into(), + ::UniversalLocation::get(), + ) + .expect("Location reanchor failed"); + let weight = ::WeightInfo::run_xcmp_task(); + let expected_schedule_fee_amount = if schedule_fee_location == MultiLocation::default() { + calculate_local_action_schedule_fee(weight, num_of_execution) + } else { + let fee_per_second = + get_fee_per_second(&schedule_fee_location).expect("Get fee per second should work"); + fee_per_second * (weight.ref_time() as u128) * (num_of_execution as u128) / + (WEIGHT_REF_TIME_PER_SECOND as u128) + }; + expected_schedule_fee_amount +} + // when schedule with a Fixed Time schedule and passing an epoch that isn't the // beginning of hour, raise an error // the smallest granularity unit we allow is hour @@ -275,9 +359,248 @@ fn schedule_transfer_with_dynamic_dispatch() { }) } +#[test] +fn calculate_auto_compound_action_schedule_fee_amount_works() { + new_test_ext(START_BLOCK_TIME).execute_with(|| { + let num_of_execution = generate_random_num(1, 20); + let delegator = AccountId32::new(ALICE); + let collator = AccountId32::new(BOB); + let action = Action::AutoCompoundDelegatedStake { + delegator, + collator, + account_minimum: 100u128.into(), + }; + + let fee_amount = AutomationTime::calculate_schedule_fee_amount(&action, num_of_execution) + .expect(EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT); + + let weight = ::WeightInfo::run_auto_compound_delegated_stake_task(); + let expected_schedule_fee_amount = + calculate_local_action_schedule_fee(weight, num_of_execution); + + assert_eq!(fee_amount, expected_schedule_fee_amount); + }) +} + +#[test] +fn calculate_dynamic_dispatch_action_schedule_fee_amount_works() { + new_test_ext(START_BLOCK_TIME).execute_with(|| { + let num_of_execution = generate_random_num(1, 20); + let call: ::RuntimeCall = + frame_system::Call::remark_with_event { remark: vec![0] }.into(); + let action = Action::DynamicDispatch { encoded_call: call.encode() }; + + let fee_amount = AutomationTime::calculate_schedule_fee_amount(&action, num_of_execution) + .expect(EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT); + + let weight = ::WeightInfo::run_dynamic_dispatch_action() + .saturating_add(call.get_dispatch_info().weight); + let expected_schedule_fee_amount = + calculate_local_action_schedule_fee(weight, num_of_execution); + + assert_eq!(fee_amount, expected_schedule_fee_amount); + }) +} + +#[test] +fn calculate_xcmp_action_schedule_fee_amount_works() { + new_test_ext(START_BLOCK_TIME).execute_with(|| { + let num_of_execution = generate_random_num(1, 20); + let action = create_xcmp_action(XcmpActionParams::default()); + let fee_amount = AutomationTime::calculate_schedule_fee_amount(&action, num_of_execution) + .expect(EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT); + let expected_schedule_fee_amount = calculate_expected_xcmp_action_schedule_fee( + action.schedule_fee_location::(), + num_of_execution, + ); + assert_eq!(fee_amount, expected_schedule_fee_amount); + }) +} + +#[test] +fn calculate_xcmp_action_schedule_fee_amount_with_different_schedule_fees_works() { + new_test_ext(START_BLOCK_TIME).execute_with(|| { + ASSET_FEE_PER_SECOND.into_iter().for_each(|fee| { + let num_of_execution = generate_random_num(1, 20); + let action = create_xcmp_action(XcmpActionParams { + schedule_fee: fee.asset_location.clone(), + ..XcmpActionParams::default() + }); + + let fee_amount = + AutomationTime::calculate_schedule_fee_amount(&action, num_of_execution) + .expect(EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT); + + let expected_schedule_fee_amount = + calculate_expected_xcmp_action_schedule_fee(fee.asset_location, num_of_execution); + + assert_eq!(fee_amount, expected_schedule_fee_amount); + }); + }) +} + +#[test] +fn calculate_xcmp_action_schedule_fee_amount_with_absolute_or_relative_native_schedule_fee_works() { + new_test_ext(START_BLOCK_TIME).execute_with(|| { + let num_of_execution = generate_random_num(1, 20); + + let action_absolute = create_xcmp_action(XcmpActionParams { + schedule_fee: MultiLocation::new( + 1, + X1(Parachain(::SelfParaId::get().into())), + ), + ..XcmpActionParams::default() + }); + let fee_amount_abosolute = + AutomationTime::calculate_schedule_fee_amount(&action_absolute, num_of_execution) + .expect(EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT); + + let action_relative = create_xcmp_action(XcmpActionParams { + schedule_fee: MultiLocation::new(0, Here), + ..XcmpActionParams::default() + }); + let fee_amount_relative = + AutomationTime::calculate_schedule_fee_amount(&action_relative, num_of_execution) + .expect(EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT); + + let expected_schedule_fee_amount = calculate_expected_xcmp_action_schedule_fee( + MultiLocation::new(0, Here), + num_of_execution, + ); + + assert_eq!(fee_amount_abosolute, fee_amount_relative); + assert_eq!(fee_amount_abosolute, expected_schedule_fee_amount); + }) +} + +#[test] +fn calculate_xcmp_action_schedule_fee_amount_with_different_destination_returns_same_result() { + new_test_ext(START_BLOCK_TIME).execute_with(|| { + let num_of_execution = generate_random_num(1, 20); + + let action = create_xcmp_action(XcmpActionParams { + destination: MultiLocation::new(1, X1(Parachain(PARA_ID))), + ..XcmpActionParams::default() + }); + let fee_amount = AutomationTime::calculate_schedule_fee_amount(&action, num_of_execution) + .expect(EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT); + + let action_diffrent_dest = create_xcmp_action(XcmpActionParams { + destination: MultiLocation::new(1, X1(Parachain(3000))), + ..XcmpActionParams::default() + }); + let fee_amount_diffrent_dest = + AutomationTime::calculate_schedule_fee_amount(&action_diffrent_dest, num_of_execution) + .expect(EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT); + + assert_eq!(fee_amount, fee_amount_diffrent_dest); + }) +} + +#[test] +fn calculate_xcmp_action_schedule_fee_amount_with_different_execution_fee_returns_same_result() { + new_test_ext(START_BLOCK_TIME).execute_with(|| { + let num_of_execution = generate_random_num(1, 20); + + let action = create_xcmp_action(XcmpActionParams { + execution_fee: AssetPayment { + asset_location: MOONBASE_ASSET_LOCATION.into(), + amount: 100, + }, + ..XcmpActionParams::default() + }); + let fee_amount = AutomationTime::calculate_schedule_fee_amount(&action, num_of_execution) + .expect(EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT); + + let action_diffrent_execution_fee = create_xcmp_action(XcmpActionParams { + execution_fee: AssetPayment { + asset_location: MultiLocation::new(1, X1(Parachain(3000))).into(), + amount: 300, + }, + ..XcmpActionParams::default() + }); + let fee_amount_diffrent_execution_fee = AutomationTime::calculate_schedule_fee_amount( + &action_diffrent_execution_fee, + num_of_execution, + ) + .expect(EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT); + + assert_eq!(fee_amount, fee_amount_diffrent_execution_fee); + }) +} + +#[test] +fn calculate_xcmp_action_schedule_fee_amount_with_different_instruction_sequence_returns_same_result( +) { + new_test_ext(START_BLOCK_TIME).execute_with(|| { + let num_of_execution = generate_random_num(1, 20); + + let action = create_xcmp_action(XcmpActionParams { + instruction_sequence: InstructionSequence::PayThroughSovereignAccount, + ..XcmpActionParams::default() + }); + let fee_amount = AutomationTime::calculate_schedule_fee_amount(&action, num_of_execution) + .expect(EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT); + + let action_diff_instruction_sequence = create_xcmp_action(XcmpActionParams { + instruction_sequence: InstructionSequence::PayThroughRemoteDerivativeAccount, + ..XcmpActionParams::default() + }); + let fee_amount_diff_instruction_sequence = AutomationTime::calculate_schedule_fee_amount( + &action_diff_instruction_sequence, + num_of_execution, + ) + .expect(EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT); + + assert_eq!(fee_amount, fee_amount_diff_instruction_sequence); + }) +} + +#[test] +fn calculate_xcmp_action_schedule_fee_amount_with_different_schedule_as_returns_same_result() { + new_test_ext(START_BLOCK_TIME).execute_with(|| { + let num_of_execution = generate_random_num(1, 20); + + let action = create_xcmp_action(XcmpActionParams { + schedule_as: Some(ALICE.into()), + ..XcmpActionParams::default() + }); + let fee_amount = AutomationTime::calculate_schedule_fee_amount(&action, num_of_execution) + .expect(EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT); + + let action_different_schedule_as = create_xcmp_action(XcmpActionParams { + schedule_as: Some(BOB.into()), + ..XcmpActionParams::default() + }); + let fee_amount_different_schedule_as = AutomationTime::calculate_schedule_fee_amount( + &action_different_schedule_as, + num_of_execution, + ) + .expect(EXPECT_CALCULATE_SCHEDULE_FEE_AMOUNT); + + assert_eq!(fee_amount, fee_amount_different_schedule_as); + }) +} + +#[test] +fn calculate_xcmp_action_schedule_fee_amount_with_unknown_schedule_fees_fails() { + new_test_ext(START_BLOCK_TIME).execute_with(|| { + let num_of_execution = generate_random_num(1, 20); + let action = create_xcmp_action(XcmpActionParams { + schedule_fee: UNKNOWN_SCHEDULE_FEE, + ..XcmpActionParams::default() + }); + assert_noop!( + AutomationTime::calculate_schedule_fee_amount(&action, num_of_execution), + sp_runtime::DispatchError::Other("CouldNotDetermineFeePerSecond"), + ); + }) +} + #[test] fn schedule_xcmp_works() { new_test_ext(START_BLOCK_TIME).execute_with(|| { + let destination = MultiLocation::new(1, X1(Parachain(PARA_ID))); let alice = AccountId32::new(ALICE); let call: Vec = vec![2, 4, 5]; // Funds including XCM fees @@ -287,11 +610,15 @@ fn schedule_xcmp_works() { RuntimeOrigin::signed(alice.clone()), vec![50], ScheduleParam::Fixed { execution_times: vec![SCHEDULED_TIME] }, - PARA_ID.try_into().unwrap(), - NATIVE, - MultiLocation::new(1, X1(Parachain(PARA_ID.into()))).into(), + Box::new(destination.into()), + Box::new(NATIVE_LOCATION.into()), + Box::new(AssetPayment { + asset_location: MultiLocation::new(0, Here).into(), + amount: 10 + }), call.clone(), Weight::from_ref_time(100_000), + Weight::from_ref_time(200_000), )); }) } @@ -300,6 +627,7 @@ fn schedule_xcmp_works() { fn schedule_xcmp_through_proxy_works() { new_test_ext(START_BLOCK_TIME).execute_with(|| { let provided_id = vec![50]; + let destination = MultiLocation::new(1, X1(Parachain(PARA_ID.into()))); let delegator_account = AccountId32::new(DELEGATOR_ACCOUNT); let proxy_account = AccountId32::new(PROXY_ACCOUNT); let call: Vec = vec![2, 4, 5]; @@ -311,11 +639,15 @@ fn schedule_xcmp_through_proxy_works() { RuntimeOrigin::signed(proxy_account.clone()), provided_id, ScheduleParam::Fixed { execution_times: vec![SCHEDULED_TIME] }, - PARA_ID.try_into().unwrap(), - NATIVE, - MultiLocation::new(1, X1(Parachain(PARA_ID.into()))).into(), + Box::new(destination.clone().into()), + Box::new(MultiLocation::default().into()), + Box::new(AssetPayment { + asset_location: destination.into(), + amount: 10, + }), call.clone(), Weight::from_ref_time(100_000), + Weight::from_ref_time(200_000), delegator_account.clone(), )); @@ -346,6 +678,7 @@ fn schedule_xcmp_through_proxy_same_as_delegator_account() { let provided_id = vec![50]; let delegator_account = AccountId32::new(ALICE); let call: Vec = vec![2, 4, 5]; + let destination = MultiLocation::new(1, X1(Parachain(PARA_ID.into()))); // Funds including XCM fees get_xcmp_funds(delegator_account.clone()); @@ -355,11 +688,12 @@ fn schedule_xcmp_through_proxy_same_as_delegator_account() { RuntimeOrigin::signed(delegator_account.clone()), provided_id, ScheduleParam::Fixed { execution_times: vec![SCHEDULED_TIME] }, - PARA_ID.try_into().unwrap(), - NATIVE, - MultiLocation::new(1, X1(Parachain(PARA_ID.into()))).into(), + Box::new(destination.clone().into()), + Box::new(MultiLocation::default().into()), + Box::new(AssetPayment { asset_location: destination.into(), amount: 10 }), call.clone(), Weight::from_ref_time(100_000), + Weight::from_ref_time(200_000), delegator_account.clone(), ), sp_runtime::DispatchError::Other("proxy error: expected `ProxyType::Any`"), @@ -370,8 +704,10 @@ fn schedule_xcmp_through_proxy_same_as_delegator_account() { #[test] fn schedule_xcmp_fails_if_not_enough_funds() { new_test_ext(START_BLOCK_TIME).execute_with(|| { + let para_id: u32 = 1000; let alice = AccountId32::new(ALICE); let call: Vec = vec![2, 4, 5]; + let destination = MultiLocation::new(1, X1(Parachain(para_id))); // Funds not including XCM fees get_minimum_funds(alice.clone(), 1); @@ -380,11 +716,15 @@ fn schedule_xcmp_fails_if_not_enough_funds() { RuntimeOrigin::signed(alice.clone()), vec![50], ScheduleParam::Fixed { execution_times: vec![SCHEDULED_TIME] }, - PARA_ID.try_into().unwrap(), - NATIVE, - MultiLocation::new(1, X1(Parachain(PARA_ID.into()))).into(), + Box::new(destination.into()), + Box::new(NATIVE_LOCATION.into()), + Box::new(AssetPayment { + asset_location: MultiLocation::new(0, Here).into(), + amount: 10000000000000 + }), call.clone(), Weight::from_ref_time(100_000), + Weight::from_ref_time(200_000), ), Error::::InsufficientBalance, ); @@ -1725,18 +2065,23 @@ fn trigger_tasks_completes_some_native_transfer_tasks() { #[test] fn trigger_tasks_completes_some_xcmp_tasks() { new_test_ext(START_BLOCK_TIME).execute_with(|| { - let para_id = PARA_ID.try_into().unwrap(); + let destination = MultiLocation::new(1, X1(Parachain(PARA_ID))); let task_id = add_task_to_task_queue( ALICE, vec![40], vec![SCHEDULED_TIME], Action::XCMP { - para_id, - currency_id: NATIVE, - xcm_asset_location: MultiLocation::new(1, X1(Parachain(para_id.into()))).into(), + destination: destination.clone(), + schedule_fee: NATIVE_LOCATION, + execution_fee: AssetPayment { + asset_location: MultiLocation::new(0, Here).into(), + amount: 10, + }, encoded_call: vec![3, 4, 5], encoded_call_weight: Weight::from_ref_time(100_000), + overall_weight: Weight::from_ref_time(200_000), schedule_as: None, + instruction_sequence: InstructionSequence::PayThroughSovereignAccount, }, ); @@ -1748,7 +2093,7 @@ fn trigger_tasks_completes_some_xcmp_tasks() { assert_eq!( events(), [RuntimeEvent::AutomationTime(crate::Event::XcmpTaskSucceeded { - para_id: PARA_ID.try_into().unwrap(), + destination, task_id, })] ); diff --git a/pallets/automation-time/src/types.rs b/pallets/automation-time/src/types.rs index 2bf30e5e4..9dda6067e 100644 --- a/pallets/automation-time/src/types.rs +++ b/pallets/automation-time/src/types.rs @@ -1,12 +1,10 @@ -use crate::{weights::WeightInfo, Config, Error, Pallet}; +use crate::{weights::WeightInfo, Config, Error, InstructionSequence, Pallet}; use frame_support::{dispatch::GetDispatchInfo, pallet_prelude::*, traits::Get}; use sp_runtime::traits::{AtLeast32BitUnsigned, CheckedConversion}; use sp_std::prelude::*; -use cumulus_primitives_core::ParaId; - use pallet_automation_time_rpc_runtime_api::AutomationAction; use xcm::{latest::prelude::*, VersionedMultiLocation}; @@ -14,9 +12,16 @@ use xcm::{latest::prelude::*, VersionedMultiLocation}; pub type Seconds = u64; pub type UnixTime = u64; +/// The struct that stores execution payment for a task. +#[derive(Debug, Encode, Eq, PartialEq, Decode, TypeInfo, Clone)] +pub struct AssetPayment { + pub asset_location: VersionedMultiLocation, + pub amount: u128, +} + /// The enum that stores all action specific data. #[derive(Clone, Debug, Eq, PartialEq, Encode, Decode, TypeInfo)] -pub enum Action { +pub enum Action { Notify { message: Vec, }, @@ -26,12 +31,14 @@ pub enum Action { amount: Balance, }, XCMP { - para_id: ParaId, - currency_id: CurrencyId, - xcm_asset_location: VersionedMultiLocation, + destination: MultiLocation, + schedule_fee: MultiLocation, + execution_fee: AssetPayment, encoded_call: Vec, encoded_call_weight: Weight, + overall_weight: Weight, schedule_as: Option, + instruction_sequence: InstructionSequence, }, AutoCompoundDelegatedStake { delegator: AccountId, @@ -43,7 +50,7 @@ pub enum Action { }, } -impl Action { +impl Action { pub fn execution_weight(&self) -> Result { let weight = match self { Action::Notify { .. } => ::WeightInfo::run_notify_task(), @@ -61,20 +68,16 @@ impl Action(&self) -> CurrencyId - where - CurrencyId: From, - { + pub fn schedule_fee_location(&self) -> MultiLocation { match self { - Action::XCMP { currency_id, .. } => currency_id.clone(), - _ => CurrencyId::from(T::GetNativeCurrencyId::get()), + Action::XCMP { schedule_fee, .. } => (*schedule_fee).clone(), + _ => MultiLocation::default(), } } } -impl - From for Action +impl From + for Action { fn from(a: AutomationAction) -> Self { let default_account = @@ -88,12 +91,17 @@ impl Action::XCMP { - para_id: ParaId::from(2114 as u32), - currency_id: CurrencyId::default(), - xcm_asset_location: MultiLocation::new(1, X1(Parachain(2114))).into(), + destination: MultiLocation::default(), + schedule_fee: MultiLocation::default(), + execution_fee: AssetPayment { + asset_location: MultiLocation::default().into(), + amount: 0, + }, encoded_call: vec![0], encoded_call_weight: Weight::zero(), + overall_weight: Weight::zero(), schedule_as: None, + instruction_sequence: InstructionSequence::PayThroughSovereignAccount, }, AutomationAction::AutoCompoundDelegatedStake => Action::AutoCompoundDelegatedStake { delegator: default_account.clone(), @@ -200,16 +208,14 @@ impl Schedule { /// The struct that stores all information needed for a task. #[derive(Debug, Encode, Decode, TypeInfo, Clone)] #[scale_info(skip_type_params(MaxExecutionTimes))] -pub struct Task { +pub struct Task { pub owner_id: AccountId, pub provided_id: Vec, pub schedule: Schedule, - pub action: Action, + pub action: Action, } -impl PartialEq - for Task -{ +impl PartialEq for Task { fn eq(&self, other: &Self) -> bool { self.owner_id == other.owner_id && self.provided_id == other.provided_id && @@ -218,16 +224,14 @@ impl PartialEq } } -impl Eq for Task {} - -use sp_runtime::print; +impl Eq for Task {} -impl Task { +impl Task { pub fn new( owner_id: AccountId, provided_id: Vec, schedule: Schedule, - action: Action, + action: Action, ) -> Self { Self { owner_id, provided_id, schedule, action } } @@ -249,19 +253,25 @@ impl Task owner_id: AccountId, provided_id: Vec, execution_times: Vec, - para_id: ParaId, - currency_id: CurrencyId, - xcm_asset_location: VersionedMultiLocation, + destination: MultiLocation, + schedule_fee: MultiLocation, + execution_fee: AssetPayment, encoded_call: Vec, encoded_call_weight: Weight, + overall_weight: Weight, + instruction_sequence: InstructionSequence, ) -> Result { + let destination = + MultiLocation::try_from(destination).map_err(|_| Error::::BadVersion)?; let action = Action::XCMP { - para_id, - currency_id, - xcm_asset_location, + destination, + schedule_fee, + execution_fee, encoded_call, encoded_call_weight, + overall_weight, schedule_as: None, + instruction_sequence, }; let schedule = Schedule::new_fixed_schedule::(execution_times)?; Ok(Self::new(owner_id, provided_id, schedule, action)) @@ -334,7 +344,7 @@ impl ScheduledTasks { pub fn try_push( &mut self, task_id: TaskId, - task: &Task, + task: &Task, ) -> Result<&mut Self, DispatchError> where AccountId: Clone, diff --git a/pallets/automation-time/src/weights.rs b/pallets/automation-time/src/weights.rs index 91b1d87b2..4322110b9 100644 --- a/pallets/automation-time/src/weights.rs +++ b/pallets/automation-time/src/weights.rs @@ -69,7 +69,7 @@ //:append_to_missed_tasks 3_079_147 //:update_scheduled_task_queue 33_968_000 //:shift_missed_tasks 16_915_000 -//:migration_upgrade_weight_struct 12_312_843 +//:migration_upgrade_xcmp_task 12_312_843 #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -103,7 +103,7 @@ pub trait WeightInfo { fn append_to_missed_tasks(v: u32, ) -> Weight; fn update_scheduled_task_queue() -> Weight; fn shift_missed_tasks() -> Weight; - fn migration_upgrade_weight_struct(v: u32, ) -> Weight; + fn migration_upgrade_xcmp_task(v: u32, ) -> Weight; } /// Weights for pallet_automation_time using the Substrate node and recommended hardware. @@ -424,7 +424,7 @@ impl WeightInfo for SubstrateWeight { // Storage: AutomationTime AccountTasks (r:101 w:100) // Proof Skipped: AutomationTime AccountTasks (max_values: None, max_size: None, mode: Measured) /// The range of component `v` is `[1, 100]`. - fn migration_upgrade_weight_struct(v: u32, ) -> Weight { + fn migration_upgrade_xcmp_task(v: u32, ) -> Weight { Weight::from_ref_time(12_312_843 as u64) // Standard Error: 14_011 .saturating_add(Weight::from_ref_time(8_424_617 as u64).saturating_mul(v as u64)) @@ -751,7 +751,7 @@ impl WeightInfo for () { // Storage: AutomationTime AccountTasks (r:101 w:100) // Proof Skipped: AutomationTime AccountTasks (max_values: None, max_size: None, mode: Measured) /// The range of component `v` is `[1, 100]`. - fn migration_upgrade_weight_struct(v: u32, ) -> Weight { + fn migration_upgrade_xcmp_task(v: u32, ) -> Weight { Weight::from_ref_time(12_312_843 as u64) // Standard Error: 14_011 .saturating_add(Weight::from_ref_time(8_424_617 as u64).saturating_mul(v as u64)) diff --git a/pallets/xcmp-handler/Cargo.toml b/pallets/xcmp-handler/Cargo.toml index 584640d7c..566b0a02e 100644 --- a/pallets/xcmp-handler/Cargo.toml +++ b/pallets/xcmp-handler/Cargo.toml @@ -40,6 +40,9 @@ polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-f xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.38" } xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.38" } +# ORML +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } + [dev-dependencies] # Substrate pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } @@ -65,6 +68,7 @@ std = [ "frame-benchmarking/std", "frame-support/std", "frame-system/std", + "orml-traits/std", "polkadot-parachain/std", "scale-info/std", "sp-runtime/std", diff --git a/pallets/xcmp-handler/src/benchmarking.rs b/pallets/xcmp-handler/src/benchmarking.rs deleted file mode 100644 index f7867c863..000000000 --- a/pallets/xcmp-handler/src/benchmarking.rs +++ /dev/null @@ -1,52 +0,0 @@ -// This file is part of OAK Blockchain. - -// Copyright (C) 2022 OAK Network -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::*; - -#[allow(unused)] -use crate::Pallet as XcmpHandler; -use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, Box}; -use frame_system::RawOrigin; - -use xcm::{latest::prelude::*, VersionedMultiLocation}; - -benchmarks! { - set_asset_config { - let location = MultiLocation::new(1, X1(Parachain(1000))); - let versioned_location: VersionedMultiLocation = location.clone().into(); - let xcm_data = XcmAssetConfig { fee_per_second: 100, instruction_weight: Weight::from_ref_time(1_000), flow: XcmFlow::Normal }; - }: set_asset_config(RawOrigin::Root, Box::new(versioned_location), xcm_data.clone()) - verify { - assert_eq!(DestinationAssetConfig::::get(location).unwrap(), xcm_data); - } - - remove_asset_config { - let location = MultiLocation::new(1, X1(Parachain(1000))); - let versioned_location: VersionedMultiLocation = location.clone().into(); - let xcm_data = - XcmAssetConfig { fee_per_second: 100, instruction_weight: Weight::from_ref_time(1_000), flow: XcmFlow::Normal }; - DestinationAssetConfig::::insert(location.clone(), xcm_data); - - }: remove_asset_config(RawOrigin::Root, Box::new(versioned_location)) - verify { - if let Some(_) = DestinationAssetConfig::::get(location) { - panic!("There should be no data set") - }; - } -} - -impl_benchmark_test_suite!(XcmpHandler, crate::mock::new_test_ext(None), crate::mock::Test,); diff --git a/pallets/xcmp-handler/src/lib.rs b/pallets/xcmp-handler/src/lib.rs index f36196fe8..6e8041ab5 100644 --- a/pallets/xcmp-handler/src/lib.rs +++ b/pallets/xcmp-handler/src/lib.rs @@ -37,32 +37,21 @@ mod mock; #[cfg(test)] mod tests; -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; - pub mod migrations; -pub mod weights; -pub use weights::WeightInfo; use cumulus_primitives_core::ParaId; use frame_support::pallet_prelude::*; -use xcm::{latest::prelude::*, VersionedMultiLocation}; +use xcm::latest::prelude::*; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{ - dispatch::DispatchResultWithPostInfo, traits::Currency, - weights::constants::WEIGHT_REF_TIME_PER_SECOND, - }; - use frame_system::pallet_prelude::*; + use frame_support::traits::Currency; use polkadot_parachain::primitives::Sibling; use sp_runtime::traits::{AccountIdConversion, Convert, SaturatedConversion}; use sp_std::prelude::*; use xcm_executor::traits::WeightBounds; - type ParachainId = u32; - pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -100,9 +89,6 @@ pub mod pallet { /// This chain's Universal Location. type UniversalLocation: Get; - /// Weight information for extrinsics in this module. - type WeightInfo: WeightInfo; - /// Utility for sending XCM messages. type XcmSender: SendXcm; @@ -123,7 +109,7 @@ pub mod pallet { pub enum Event { /// XCM sent to target chain. XcmSent { - para_id: ParachainId, + destination: MultiLocation, }, /// XCM transacted in local chain. XcmTransactedLocally, @@ -138,11 +124,11 @@ pub mod pallet { dest: T::AccountId, error: DispatchError, }, - DestAssetConfigChanged { - asset_location: MultiLocation, + TransactInfoChanged { + destination: MultiLocation, }, - DestAssetConfigRemoved { - asset_location: MultiLocation, + TransactInfoRemoved { + destination: MultiLocation, }, } @@ -166,95 +152,13 @@ pub mod pallet { /// to be interpreted. BadVersion, // Asset not found - AssetNotFound, + TransactInfoNotFound, } - /// Stores all configuration needed to send an XCM message for a given asset location. - #[derive(Clone, Debug, Encode, Decode, PartialEq, TypeInfo)] - pub struct XcmAssetConfig { - pub fee_per_second: u128, - /// The UnitWeightCost of a single instruction on the target chain - pub instruction_weight: Weight, - /// The desired instruction flow for the target chain - pub flow: XcmFlow, - } - - /// Stores the config for an asset in its reserve chain. - #[pallet::storage] - #[pallet::getter(fn dest_asset_config)] - pub type DestinationAssetConfig = - StorageMap<_, Twox64Concat, MultiLocation, XcmAssetConfig>; - #[pallet::call] - impl Pallet { - /// Set asset config for a given asset location - #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::set_asset_config())] - pub fn set_asset_config( - origin: OriginFor, - asset_location: Box, - xcm_asset_config: XcmAssetConfig, - ) -> DispatchResultWithPostInfo { - ensure_root(origin)?; - - let asset_location = - MultiLocation::try_from(*asset_location).map_err(|()| Error::::BadVersion)?; - - DestinationAssetConfig::::insert(&asset_location, &xcm_asset_config); - - Self::deposit_event(Event::DestAssetConfigChanged { asset_location }); - - Ok(().into()) - } - - /// Remove asset config for a given asset location - #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::remove_asset_config())] - pub fn remove_asset_config( - origin: OriginFor, - asset_location: Box, - ) -> DispatchResultWithPostInfo { - ensure_root(origin)?; - - let asset_location = - MultiLocation::try_from(*asset_location).map_err(|()| Error::::BadVersion)?; - - DestinationAssetConfig::::take(&asset_location).ok_or(Error::::AssetNotFound)?; - - Self::deposit_event(Event::DestAssetConfigRemoved { asset_location }); - - Ok(().into()) - } - } + impl Pallet {} impl Pallet { - /// Get the xcm fee and weight for a transact xcm for a given asset location. - pub fn calculate_xcm_fee_and_weight( - para_id: ParachainId, - location: MultiLocation, - transact_encoded_call_weight: Weight, - ) -> Result<(u128, Weight, XcmAssetConfig), DispatchError> { - let xcm_data = DestinationAssetConfig::::get(location.clone()) - .ok_or(Error::::AssetNotFound)?; - - let (_, target_instructions) = - Self::xcm_instruction_skeleton(para_id, location, xcm_data.clone())?; - let weight = xcm_data - .instruction_weight - .checked_mul(target_instructions.len() as u64) - .ok_or(Error::::WeightOverflow)? - .checked_add(&transact_encoded_call_weight) - .ok_or(Error::::WeightOverflow)?; - - let fee = xcm_data - .fee_per_second - .checked_mul(weight.ref_time() as u128) - .ok_or(Error::::FeeOverflow) - .map(|raw_fee| raw_fee / (WEIGHT_REF_TIME_PER_SECOND as u128))?; - - Ok((fee, weight, xcm_data)) - } - /// Get the instructions for a transact xcm. /// Currently we only support instructions if the currency is the local chain's. /// @@ -262,43 +166,43 @@ pub mod pallet { /// The first is to execute locally. /// The second is to execute on the target chain. pub fn get_instruction_set( - para_id: ParachainId, + destination: MultiLocation, asset_location: MultiLocation, + fee: u128, caller: T::AccountId, transact_encoded_call: Vec, transact_encoded_call_weight: Weight, + overall_weight: Weight, + flow: InstructionSequence, ) -> Result< (xcm::latest::Xcm<::RuntimeCall>, xcm::latest::Xcm<()>), DispatchError, > { - let (fee, weight, xcm_data) = Self::calculate_xcm_fee_and_weight( - para_id, - asset_location.clone(), - transact_encoded_call_weight, - )?; - let descend_location: Junctions = T::AccountIdToMultiLocation::convert(caller) .try_into() .map_err(|_| Error::::FailedMultiLocationToJunction)?; - let instructions = match xcm_data.flow { - XcmFlow::Normal => Self::get_local_currency_instructions( - para_id, - descend_location, - transact_encoded_call, - transact_encoded_call_weight, - weight, - fee, - )?, - XcmFlow::Alternate => Self::get_alternate_flow_instructions( - para_id, - asset_location, - descend_location, - transact_encoded_call, - transact_encoded_call_weight, - weight, - fee, - )?, + let instructions = match flow { + InstructionSequence::PayThroughSovereignAccount => + Self::get_local_currency_instructions( + destination, + asset_location, + descend_location, + transact_encoded_call, + transact_encoded_call_weight, + overall_weight, + fee, + )?, + InstructionSequence::PayThroughRemoteDerivativeAccount => + Self::get_alternate_flow_instructions( + destination, + asset_location, + descend_location, + transact_encoded_call, + transact_encoded_call_weight, + overall_weight, + fee, + )?, }; Ok(instructions) @@ -318,41 +222,37 @@ pub mod pallet { /// - RefundSurplus /// - DepositAsset pub fn get_local_currency_instructions( - para_id: ParachainId, + destination: MultiLocation, + asset_location: MultiLocation, descend_location: Junctions, transact_encoded_call: Vec, transact_encoded_call_weight: Weight, - xcm_weight: Weight, + overall_weight: Weight, fee: u128, ) -> Result< (xcm::latest::Xcm<::RuntimeCall>, xcm::latest::Xcm<()>), DispatchError, > { // XCM for local chain - let local_asset = MultiAsset { - id: Concrete(MultiLocation::new(0, Here)), - fun: Fungibility::Fungible(fee), - }; + let local_asset = + MultiAsset { id: Concrete(asset_location), fun: Fungibility::Fungible(fee) }; let local_xcm = Xcm(vec![ WithdrawAsset::<::RuntimeCall>(local_asset.clone().into()), DepositAsset::<::RuntimeCall> { assets: Wild(All), - beneficiary: MultiLocation { parents: 1, interior: X1(Parachain(para_id)) }, + beneficiary: destination, }, ]); // XCM for target chain let target_asset = local_asset - .reanchored( - &MultiLocation::new(1, X1(Parachain(para_id.into()))), - T::UniversalLocation::get(), - ) + .reanchored(&destination, T::UniversalLocation::get()) .map_err(|_| Error::::CannotReanchor)?; let target_xcm = Xcm(vec![ ReserveAssetDeposited::<()>(target_asset.clone().into()), - BuyExecution::<()> { fees: target_asset, weight_limit: Limited(xcm_weight) }, + BuyExecution::<()> { fees: target_asset, weight_limit: Limited(overall_weight) }, DescendOrigin::<()>(descend_location), Transact::<()> { origin_kind: OriginKind::SovereignAccount, @@ -384,7 +284,7 @@ pub mod pallet { /// - RefundSurplus /// - DepositAsset fn get_alternate_flow_instructions( - para_id: ParachainId, + destination: MultiLocation, asset_location: MultiLocation, descend_location: Junctions, transact_encoded_call: Vec, @@ -398,10 +298,7 @@ pub mod pallet { // XCM for target chain let target_asset = MultiAsset { id: Concrete(asset_location), fun: Fungibility::Fungible(fee) } - .reanchored( - &MultiLocation::new(1, X1(Parachain(para_id.into()))), - T::UniversalLocation::get(), - ) + .reanchored(&destination, T::UniversalLocation::get()) .map_err(|_| Error::::CannotReanchor)?; let target_xcm = Xcm(vec![ @@ -456,26 +353,24 @@ pub mod pallet { /// Send XCM instructions to parachain. /// pub fn transact_in_target_chain( - para_id: ParachainId, + destination: MultiLocation, target_instructions: xcm::latest::Xcm<()>, ) -> Result<(), DispatchError> { #[allow(unused_variables)] - let destination_location = Junction::Parachain(para_id.into()); + let destination_location = destination.clone(); #[cfg(all(not(test), feature = "runtime-benchmarks"))] - let destination_location: Junctions = Here; + let destination_location = MultiLocation::new(1, Here); // Send to target chain - send_xcm::( - MultiLocation::new(1, destination_location), - target_instructions, - ) - .map_err(|error| { - log::error!("Failed to send xcm to {:?} with {:?}", para_id, error); - Error::::ErrorSendingXcmToTarget - })?; + send_xcm::(destination_location, target_instructions).map_err( + |error| { + log::error!("Failed to send xcm to {:?} with {:?}", destination, error); + Error::::ErrorSendingXcmToTarget + }, + )?; - Self::deposit_event(Event::XcmSent { para_id }); + Self::deposit_event(Event::XcmSent { destination }); Ok(().into()) } @@ -487,22 +382,28 @@ pub mod pallet { /// Execute local transact instructions. /// Send target transact instructions. pub fn transact_xcm( - para_id: ParachainId, - location: MultiLocation, + destination: MultiLocation, + asset_location: MultiLocation, + fee: u128, caller: T::AccountId, transact_encoded_call: Vec, transact_encoded_call_weight: Weight, + overall_weight: Weight, + flow: InstructionSequence, ) -> Result<(), DispatchError> { let (local_instructions, target_instructions) = Self::get_instruction_set( - para_id, - location, + destination, + asset_location, + fee, caller, transact_encoded_call, transact_encoded_call_weight, + overall_weight, + flow, )?; Self::transact_in_local_chain(local_instructions)?; - Self::transact_in_target_chain(para_id, target_instructions)?; + Self::transact_in_target_chain(destination, target_instructions)?; Ok(().into()) } @@ -533,166 +434,59 @@ pub mod pallet { Ok(().into()) } - - /// Generates a skeleton of the instruction set for fee calculation - fn xcm_instruction_skeleton( - para_id: ParachainId, - asset_location: MultiLocation, - xcm_data: XcmAssetConfig, - ) -> Result< - (xcm::latest::Xcm<::RuntimeCall>, xcm::latest::Xcm<()>), - DispatchError, - > { - let nobody: Junctions = T::AccountIdToMultiLocation::convert( - T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) - .expect("always works"), - ) - .try_into() - .map_err(|_| Error::::FailedMultiLocationToJunction)?; - - match xcm_data.flow { - XcmFlow::Normal => Self::get_local_currency_instructions( - para_id, - nobody, - Default::default(), - Weight::zero(), - Weight::zero(), - 0u128, - ), - XcmFlow::Alternate => Self::get_alternate_flow_instructions( - para_id, - asset_location, - nobody, - Default::default(), - Weight::zero(), - Weight::zero(), - 0u128, - ), - } - } - } - - #[pallet::genesis_config] - pub struct GenesisConfig { - pub asset_data: Vec<(Vec, u128, Weight, XcmFlow)>, - } - - #[cfg(feature = "std")] - impl Default for GenesisConfig { - fn default() -> Self { - Self { asset_data: Default::default() } - } - } - - #[pallet::genesis_build] - impl GenesisBuild for GenesisConfig { - fn build(&self) { - for (location_encoded, fee_per_second, instruction_weight, flow) in - self.asset_data.iter() - { - let location = ::decode(&mut &location_encoded[..]) - .expect("Error decoding VersionedMultiLocation"); - - DestinationAssetConfig::::insert( - MultiLocation::try_from(location) - .expect("Error converting VersionedMultiLocation"), - XcmAssetConfig { - fee_per_second: *fee_per_second, - instruction_weight: *instruction_weight, - flow: *flow, - }, - ); - } - } } } pub trait XcmpTransactor { fn transact_xcm( - para_id: u32, - location: MultiLocation, + destination: MultiLocation, + asset_location: MultiLocation, + fee: u128, caller: AccountId, transact_encoded_call: sp_std::vec::Vec, transact_encoded_call_weight: Weight, + overall_weight: Weight, + flow: InstructionSequence, ) -> Result<(), sp_runtime::DispatchError>; - fn get_xcm_fee( - para_id: u32, - location: MultiLocation, - transact_encoded_call_weight: Weight, - ) -> Result; - fn pay_xcm_fee(source: AccountId, fee: u128) -> Result<(), sp_runtime::DispatchError>; - - #[cfg(feature = "runtime-benchmarks")] - fn setup_chain_asset_data( - asset_location: MultiLocation, - ) -> Result<(), sp_runtime::DispatchError>; } impl XcmpTransactor for Pallet { fn transact_xcm( - para_id: u32, - location: MultiLocation, + destination: MultiLocation, + asset_location: MultiLocation, + fee: u128, caller: T::AccountId, transact_encoded_call: sp_std::vec::Vec, transact_encoded_call_weight: Weight, + overall_weight: Weight, + flow: InstructionSequence, ) -> Result<(), sp_runtime::DispatchError> { Self::transact_xcm( - para_id.into(), - location, + destination, + asset_location, + fee, caller, transact_encoded_call, transact_encoded_call_weight, + overall_weight, + flow, )?; Ok(()).into() } - fn get_xcm_fee( - para_id: u32, - location: MultiLocation, - transact_encoded_call_weight: Weight, - ) -> Result { - let (fee, _weight, xcm_data) = - Self::calculate_xcm_fee_and_weight(para_id, location, transact_encoded_call_weight)?; - - match xcm_data.flow { - XcmFlow::Alternate => { - // In the alternate flow the fee is paid directly from the - // DescendOrigin derived account on the target chain - Ok(0u128) - }, - XcmFlow::Normal => Ok(fee), - } - } - fn pay_xcm_fee(source: T::AccountId, fee: u128) -> Result<(), sp_runtime::DispatchError> { Self::pay_xcm_fee(source, fee)?; Ok(()).into() } - - #[cfg(feature = "runtime-benchmarks")] - fn setup_chain_asset_data( - asset_location: MultiLocation, - ) -> Result<(), sp_runtime::DispatchError> { - let asset_data = XcmAssetConfig { - fee_per_second: 416_000_000_000, - instruction_weight: Weight::from_ref_time(600_000_000), - flow: XcmFlow::Normal, - }; - - DestinationAssetConfig::::insert(asset_location.clone(), asset_data); - Self::deposit_event(Event::DestAssetConfigChanged { asset_location }); - - Ok(().into()) - } } -#[derive(Clone, Copy, Debug, Encode, Decode, PartialEq, TypeInfo)] +#[derive(Clone, Copy, Debug, Encode, Eq, Decode, PartialEq, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub enum XcmFlow { - Normal, - Alternate, +pub enum InstructionSequence { + PayThroughSovereignAccount, + PayThroughRemoteDerivativeAccount, } diff --git a/pallets/xcmp-handler/src/mock.rs b/pallets/xcmp-handler/src/mock.rs index 2046f7dcd..1e6fa1d24 100644 --- a/pallets/xcmp-handler/src/mock.rs +++ b/pallets/xcmp-handler/src/mock.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{self as pallet_xcmp_handler, XcmFlow}; +use crate::{self as pallet_xcmp_handler}; use core::cell::RefCell; use frame_support::{ parameter_types, @@ -50,7 +50,6 @@ pub type CurrencyId = u32; pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); pub const LOCAL_PARA_ID: u32 = 2114; pub const NATIVE: CurrencyId = 0; -// pub const RELAY: CurrencyId = 1; frame_support::construct_runtime!( pub enum Test where @@ -316,13 +315,10 @@ impl pallet_xcmp_handler::Config for Test { type XcmExecutor = XcmExecutor; type XcmSender = TestSendXcm; type Weigher = FixedWeightBounds; - type WeightInfo = (); } // Build genesis storage according to the mock runtime. -pub fn new_test_ext( - genesis_config: Option, u128, Weight, XcmFlow)>>, -) -> sp_io::TestExternalities { +pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default() .build_storage::() .expect("Frame system builds valid default genesis config"); @@ -333,14 +329,6 @@ pub fn new_test_ext( ) .expect("Pallet Parachain info can be assimilated"); - if let Some(asset_data) = genesis_config { - GenesisBuild::::assimilate_storage( - &pallet_xcmp_handler::GenesisConfig { asset_data }, - &mut t, - ) - .expect("Pallet Parachain info can be assimilated"); - } - let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| System::set_block_number(1)); ext diff --git a/pallets/xcmp-handler/src/tests.rs b/pallets/xcmp-handler/src/tests.rs index 7e9f505c9..75b0c64ba 100644 --- a/pallets/xcmp-handler/src/tests.rs +++ b/pallets/xcmp-handler/src/tests.rs @@ -14,285 +14,57 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use crate::{mock::*, DestinationAssetConfig, Error, XcmAssetConfig, XcmFlow}; -use codec::Encode; -use frame_support::{assert_noop, assert_ok, weights::constants::WEIGHT_REF_TIME_PER_SECOND}; +use crate::{mock::*, InstructionSequence}; +use frame_support::assert_ok; use frame_system::RawOrigin; use polkadot_parachain::primitives::Sibling; use sp_runtime::traits::{AccountIdConversion, Convert}; -use xcm::{ - latest::{prelude::*, Weight}, - VersionedMultiLocation, -}; +use xcm::latest::{prelude::*, Weight}; //***************** //Extrinsics //***************** const PARA_ID: u32 = 1000; -const XCM_DATA: XcmAssetConfig = XcmAssetConfig { - fee_per_second: 50_000_000_000, - instruction_weight: Weight::from_ref_time(100_000_000), - flow: XcmFlow::Normal, -}; - -// set_asset_config -#[test] -fn set_asset_config_new_data() { - let asset_location = MultiLocation::new(1, X1(Parachain(PARA_ID))); - new_test_ext(None).execute_with(|| { - if DestinationAssetConfig::::get(asset_location.clone()).is_some() { - panic!("There should be no data set") - }; - - assert_ok!(XcmpHandler::set_asset_config( - RawOrigin::Root.into(), - Box::new(asset_location.clone().into()), - XCM_DATA - )); - assert_eq!(DestinationAssetConfig::::get(asset_location).unwrap(), XCM_DATA); - }); -} - -#[test] -fn set_asset_config_update_data() { - let asset_location = MultiLocation::new(1, X1(Parachain(PARA_ID))); - let genesis_config = vec![( - ::encode(&(asset_location.clone().into())), - XCM_DATA.fee_per_second, - XCM_DATA.instruction_weight, - XCM_DATA.flow, - )]; - - new_test_ext(Some(genesis_config)).execute_with(|| { - assert_eq!(DestinationAssetConfig::::get(asset_location.clone()).unwrap(), XCM_DATA); - - let xcm_data_new = XcmAssetConfig { - fee_per_second: 200, - instruction_weight: Weight::from_ref_time(3_000), - flow: XcmFlow::Normal, - }; - - assert_ok!(XcmpHandler::set_asset_config( - RawOrigin::Root.into(), - Box::new(asset_location.clone().into()), - xcm_data_new.clone() - )); - assert_eq!(DestinationAssetConfig::::get(asset_location).unwrap(), xcm_data_new); - }); -} - -// remove_asset_config -#[test] -fn remove_asset_config_remove_data() { - let asset_location = MultiLocation::new(1, X1(Parachain(PARA_ID))); - let genesis_config = vec![( - ::encode(&(asset_location.clone().into())), - XCM_DATA.fee_per_second, - XCM_DATA.instruction_weight, - XCM_DATA.flow, - )]; - - new_test_ext(Some(genesis_config)).execute_with(|| { - assert_ok!(XcmpHandler::remove_asset_config( - RawOrigin::Root.into(), - Box::new(asset_location.clone().into()), - )); - if DestinationAssetConfig::::get(asset_location).is_some() { - panic!("There should be no data set") - }; - }); -} - -#[test] -fn remove_asset_config_not_found() { - let asset_location = MultiLocation::new(1, X1(Parachain(PARA_ID))); - new_test_ext(None).execute_with(|| { - if DestinationAssetConfig::::get(asset_location.clone()).is_some() { - panic!("There should be no data set") - }; - assert_noop!( - XcmpHandler::remove_asset_config( - RawOrigin::Root.into(), - Box::new(asset_location.into()) - ), - Error::::AssetNotFound - ); - }); -} //***************** //Helper functions //***************** -// calculate_xcm_fee_and_weight -#[test] -fn calculate_xcm_fee_and_weight_works() { - let asset_location = MultiLocation::new(1, X1(Parachain(PARA_ID))); - let genesis_config = vec![( - ::encode(&(asset_location.clone().into())), - XCM_DATA.fee_per_second, - XCM_DATA.instruction_weight, - XCM_DATA.flow, - )]; - - new_test_ext(Some(genesis_config)).execute_with(|| { - let transact_encoded_call_weight = Weight::from_ref_time(100_000_000); - - let instruction_weights = XCM_DATA - .instruction_weight - .checked_mul(6) - .expect("instruction_weights overflow"); - let expected_weight = transact_encoded_call_weight - .checked_add(&instruction_weights) - .expect("expected_weight overflow"); - let expected_fee = XCM_DATA.fee_per_second * (expected_weight.ref_time() as u128) / - (WEIGHT_REF_TIME_PER_SECOND as u128); - assert_ok!( - XcmpHandler::calculate_xcm_fee_and_weight( - PARA_ID, - asset_location, - transact_encoded_call_weight - ), - (expected_fee, expected_weight, XCM_DATA), - ); - }); -} - -#[test] -fn calculate_xcm_fee_and_weight_fee_overflow() { - let asset_location = MultiLocation::new(1, X1(Parachain(PARA_ID))); - let gensis_config = vec![( - ::encode(&(asset_location.clone().into())), - u128::MAX, - Weight::from_ref_time(1_000), - XcmFlow::Normal, - )]; - - new_test_ext(Some(gensis_config)).execute_with(|| { - let transact_encoded_call_weight = Weight::from_ref_time(100_000_000); - - assert_noop!( - XcmpHandler::calculate_xcm_fee_and_weight( - PARA_ID, - asset_location, - transact_encoded_call_weight - ), - Error::::FeeOverflow - ); - }); -} - -#[test] -fn calculate_xcm_fee_and_weight_weight_overflow() { - let asset_location = MultiLocation::new(1, X1(Parachain(PARA_ID))); - let gensis_config = vec![( - ::encode(&(asset_location.clone().into())), - 1_000, - Weight::from_ref_time(u64::MAX), - XcmFlow::Normal, - )]; - - new_test_ext(Some(gensis_config)).execute_with(|| { - let transact_encoded_call_weight = Weight::from_ref_time(u64::MAX); - - assert_noop!( - XcmpHandler::calculate_xcm_fee_and_weight( - PARA_ID, - asset_location, - transact_encoded_call_weight - ), - Error::::WeightOverflow - ); - }); -} - -#[test] -fn calculate_xcm_fee_and_weight_no_xcm_data() { - let asset_location = MultiLocation::new(1, X1(Parachain(PARA_ID))); - new_test_ext(None).execute_with(|| { - let transact_encoded_call_weight = Weight::from_ref_time(100_000_000); - - if let Some(_) = DestinationAssetConfig::::get(asset_location.clone()) { - panic!("There should be no data set") - }; - assert_noop!( - XcmpHandler::calculate_xcm_fee_and_weight( - PARA_ID, - asset_location, - transact_encoded_call_weight - ), - Error::::AssetNotFound - ); - }); -} - -#[test] -fn calculate_xcm_fee_handles_alternate_flow() { - let para_id: u32 = 9999; - let asset_location = MultiLocation::new(1, X1(Parachain(PARA_ID))); - let genesis_config = vec![( - ::encode(&(asset_location.clone().into())), - XCM_DATA.fee_per_second, - XCM_DATA.instruction_weight, - XcmFlow::Alternate, - )]; - - new_test_ext(Some(genesis_config)).execute_with(|| { - let transact_encoded_call_weight = Weight::from_ref_time(100_000_000); - - let expected_weight = transact_encoded_call_weight + XCM_DATA.instruction_weight * 6; - assert_ok!( - XcmpHandler::calculate_xcm_fee_and_weight( - para_id, - asset_location, - transact_encoded_call_weight, - ), - (35000000, expected_weight, XcmAssetConfig { flow: XcmFlow::Alternate, ..XCM_DATA }), - ); - }); -} - // get_instruction_set #[test] fn get_instruction_set_local_currency_instructions() { + let destination = MultiLocation::new(1, X1(Parachain(PARA_ID))); let asset_location = MultiLocation::new(1, X1(Parachain(PARA_ID))); - let genesis_config = vec![( - ::encode(&(asset_location.clone().into())), - XCM_DATA.fee_per_second, - XCM_DATA.instruction_weight, - XCM_DATA.flow, - )]; - new_test_ext(Some(genesis_config)).execute_with(|| { + new_test_ext().execute_with(|| { let transact_encoded_call: Vec = vec![0, 1, 2]; let transact_encoded_call_weight = Weight::from_ref_time(100_000_000); - let (xcm_fee, xcm_weight, _) = XcmpHandler::calculate_xcm_fee_and_weight( - PARA_ID, - asset_location.clone(), - transact_encoded_call_weight, - ) - .unwrap(); + let overall_weight = Weight::from_ref_time(200_000_000); let descend_location: Junctions = AccountIdToMultiLocation::convert(ALICE).try_into().unwrap(); let expected_instructions = XcmpHandler::get_local_currency_instructions( - PARA_ID, + destination.clone(), + asset_location, descend_location, transact_encoded_call.clone(), - transact_encoded_call_weight, - xcm_weight, - xcm_fee, + transact_encoded_call_weight.clone(), + overall_weight.clone(), + 10, ) .unwrap(); assert_eq!( XcmpHandler::get_instruction_set( - PARA_ID, + destination, asset_location, + 10, ALICE, transact_encoded_call, - transact_encoded_call_weight + transact_encoded_call_weight, + overall_weight, + InstructionSequence::PayThroughSovereignAccount, ) .unwrap(), expected_instructions @@ -304,7 +76,9 @@ fn get_instruction_set_local_currency_instructions() { // TODO: use xcm_simulator to test these instructions. #[test] fn get_local_currency_instructions_works() { - new_test_ext(None).execute_with(|| { + new_test_ext().execute_with(|| { + let destination = MultiLocation::new(1, X1(Parachain(PARA_ID))); + let asset_location = MultiLocation::new(1, X1(Parachain(PARA_ID))); let transact_encoded_call: Vec = vec![0, 1, 2]; let transact_encoded_call_weight = Weight::from_ref_time(100_000_000); let xcm_weight = transact_encoded_call_weight @@ -315,7 +89,8 @@ fn get_local_currency_instructions_works() { AccountIdToMultiLocation::convert(ALICE).try_into().unwrap(); let (local, target) = XcmpHandler::get_local_currency_instructions( - PARA_ID, + destination, + asset_location, descend_location, transact_encoded_call, transact_encoded_call_weight, @@ -330,22 +105,22 @@ fn get_local_currency_instructions_works() { #[test] fn transact_in_local_chain_works() { - new_test_ext(None).execute_with(|| { + new_test_ext().execute_with(|| { + let destination = MultiLocation::new(1, X1(Parachain(PARA_ID))); + let asset_location = destination.clone(); let transact_encoded_call: Vec = vec![0, 1, 2]; let transact_encoded_call_weight = Weight::from_ref_time(100_000_000); let xcm_weight = transact_encoded_call_weight .checked_add(&Weight::from_ref_time(100_000_000)) .expect("xcm_weight overflow"); let xcm_fee = (xcm_weight.ref_time() as u128) * 5_000_000_000; - let asset = MultiAsset { - id: Concrete(MultiLocation { parents: 0, interior: Here }), - fun: Fungible(xcm_fee), - }; + let asset = MultiAsset { id: Concrete(asset_location.clone()), fun: Fungible(xcm_fee) }; let descend_location: Junctions = AccountIdToMultiLocation::convert(ALICE).try_into().unwrap(); let (local_instructions, _) = XcmpHandler::get_local_currency_instructions( - PARA_ID, + destination, + asset_location, descend_location, transact_encoded_call.clone(), transact_encoded_call_weight, @@ -376,22 +151,22 @@ fn transact_in_local_chain_works() { #[test] fn transact_in_target_chain_works() { - new_test_ext(None).execute_with(|| { + new_test_ext().execute_with(|| { + let destination = MultiLocation::new(1, X1(Parachain(PARA_ID))); + let asset_location = MultiLocation { parents: 1, interior: X1(Parachain(LOCAL_PARA_ID)) }; let transact_encoded_call: Vec = vec![0, 1, 2]; let transact_encoded_call_weight = Weight::from_ref_time(100_000_000); let xcm_weight = transact_encoded_call_weight .checked_add(&Weight::from_ref_time(100_000_000)) .expect("xcm_weight overflow"); let xcm_fee = (xcm_weight.ref_time() as u128) * 5_000_000_000; - let asset = MultiAsset { - id: Concrete(MultiLocation { parents: 1, interior: X1(Parachain(LOCAL_PARA_ID)) }), - fun: Fungible(xcm_fee), - }; + let asset = MultiAsset { id: Concrete(asset_location), fun: Fungible(xcm_fee) }; let descend_location: Junctions = AccountIdToMultiLocation::convert(ALICE).try_into().unwrap(); let (_, target_instructions) = XcmpHandler::get_local_currency_instructions( - PARA_ID, + destination.clone(), + asset_location, descend_location, transact_encoded_call.clone(), transact_encoded_call_weight, @@ -400,7 +175,7 @@ fn transact_in_target_chain_works() { ) .unwrap(); - assert_ok!(XcmpHandler::transact_in_target_chain(PARA_ID, target_instructions)); + assert_ok!(XcmpHandler::transact_in_target_chain(destination.clone(), target_instructions)); assert_eq!( sent_xcm(), vec![( @@ -435,16 +210,13 @@ fn transact_in_target_chain_works() { .to_vec()), )] ); - assert_eq!( - events(), - [RuntimeEvent::XcmpHandler(crate::Event::XcmSent { para_id: PARA_ID })] - ); + assert_eq!(events(), [RuntimeEvent::XcmpHandler(crate::Event::XcmSent { destination })]); }); } #[test] fn pay_xcm_fee_works() { - new_test_ext(None).execute_with(|| { + new_test_ext().execute_with(|| { let local_sovereign_account: AccountId = Sibling::from(LOCAL_PARA_ID).into_account_truncating(); let fee = 3_500_000; @@ -460,7 +232,7 @@ fn pay_xcm_fee_works() { #[test] fn pay_xcm_fee_keeps_wallet_alive() { - new_test_ext(None).execute_with(|| { + new_test_ext().execute_with(|| { let local_sovereign_account: AccountId = Sibling::from(LOCAL_PARA_ID).into_account_truncating(); let fee = 3_500_000; diff --git a/pallets/xcmp-handler/src/weights.rs b/pallets/xcmp-handler/src/weights.rs deleted file mode 100644 index 7e66a5a7c..000000000 --- a/pallets/xcmp-handler/src/weights.rs +++ /dev/null @@ -1,98 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Autogenerated weights for pallet_xcmp_handler -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `actions-runner-1`, CPU: `Intel(R) Xeon(R) E-2388G CPU @ 3.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("turing-dev"), DB CACHE: 1024 - -// Executed Command: -// ./oak-collator -// benchmark -// pallet -// --chain -// turing-dev -// --execution -// wasm -// --wasm-execution -// compiled -// --pallet -// pallet_xcmp_handler -// --extrinsic -// * -// --repeat -// 20 -// --steps -// 50 -// --output -// ./xcmp_handler-raw-weights.rs -// --template -// ./.maintain/frame-weight-template.hbs - -// Summary: -//:set_asset_config 10_886_000 -//:remove_asset_config 15_615_000 - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use sp_std::marker::PhantomData; - -/// Weight functions needed for pallet_xcmp_handler. -pub trait WeightInfo { - fn set_asset_config() -> Weight; - fn remove_asset_config() -> Weight; -} - -/// Weights for pallet_xcmp_handler using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - // Storage: XcmpHandler DestinationAssetConfig (r:0 w:1) - // Proof Skipped: XcmpHandler DestinationAssetConfig (max_values: None, max_size: None, mode: Measured) - fn set_asset_config() -> Weight { - Weight::from_ref_time(10_886_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: XcmpHandler DestinationAssetConfig (r:1 w:1) - // Proof Skipped: XcmpHandler DestinationAssetConfig (max_values: None, max_size: None, mode: Measured) - fn remove_asset_config() -> Weight { - Weight::from_ref_time(15_615_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } -} - -// For backwards compatibility and tests -impl WeightInfo for () { - // Storage: XcmpHandler DestinationAssetConfig (r:0 w:1) - // Proof Skipped: XcmpHandler DestinationAssetConfig (max_values: None, max_size: None, mode: Measured) - fn set_asset_config() -> Weight { - Weight::from_ref_time(10_886_000 as u64) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: XcmpHandler DestinationAssetConfig (r:1 w:1) - // Proof Skipped: XcmpHandler DestinationAssetConfig (max_values: None, max_size: None, mode: Measured) - fn remove_asset_config() -> Weight { - Weight::from_ref_time(15_615_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } -} diff --git a/runtime/neumann/Cargo.toml b/runtime/neumann/Cargo.toml index 6d27f6ac0..4b404cf6c 100644 --- a/runtime/neumann/Cargo.toml +++ b/runtime/neumann/Cargo.toml @@ -200,7 +200,6 @@ runtime-benchmarks = [ "pallet-valve/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "pallet-xcmp-handler/runtime-benchmarks", "pallet-parachain-staking/runtime-benchmarks", ] diff --git a/runtime/neumann/src/lib.rs b/runtime/neumann/src/lib.rs index 6a1b9171c..57ff379d9 100644 --- a/runtime/neumann/src/lib.rs +++ b/runtime/neumann/src/lib.rs @@ -104,6 +104,7 @@ use primitives::{ // Custom pallet imports pub use pallet_automation_price; pub use pallet_automation_time; +use pallet_xcmp_handler::InstructionSequence; use primitives::EnsureProxy; @@ -189,6 +190,9 @@ pub fn native_version() -> NativeVersion { parameter_types! { pub const RelayNetwork: NetworkId = NetworkId::Rococo; + // The universal location within the global consensus system + pub UniversalLocation: InteriorMultiLocation = + X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); } parameter_types! { @@ -883,7 +887,6 @@ impl pallet_automation_time::Config for Runtime { type Currency = Balances; type MultiCurrency = Currencies; type CurrencyId = TokenId; - type GetNativeCurrencyId = GetNativeCurrencyId; type XcmpTransactor = XcmpHandler; type FeeHandler = pallet_automation_time::FeeHandler; type DelegatorActions = ParachainStaking; @@ -892,6 +895,8 @@ impl pallet_automation_time::Config for Runtime { type Call = RuntimeCall; type ScheduleAllowList = ScheduleAllowList; type EnsureProxy = AutomationEnsureProxy; + type UniversalLocation = UniversalLocation; + type SelfParaId = parachain_info::Pallet; } impl pallet_automation_price::Config for Runtime { @@ -1000,7 +1005,7 @@ construct_runtime!( //custom pallets AutomationTime: pallet_automation_time::{Pallet, Call, Storage, Event} = 60, Vesting: pallet_vesting::{Pallet, Storage, Config, Event} = 61, - XcmpHandler: pallet_xcmp_handler::{Pallet, Call, Storage, Config, Event} = 62, + XcmpHandler: pallet_xcmp_handler::{Pallet, Call, Event} = 62, AutomationPrice: pallet_automation_price::{Pallet, Call, Storage, Event} = 200, } ); @@ -1141,15 +1146,19 @@ impl_runtime_apis! { let (action, executions) = match uxt.function { RuntimeCall::AutomationTime(pallet_automation_time::Call::schedule_xcmp_task{ - para_id, currency_id, xcm_asset_location, encoded_call, encoded_call_weight, schedule, .. + destination, schedule_fee, execution_fee, encoded_call, encoded_call_weight, overall_weight, schedule, .. }) => { - let action = Action::XCMP { para_id, currency_id, xcm_asset_location, encoded_call, encoded_call_weight, schedule_as: None }; + let destination = MultiLocation::try_from(*destination).map_err(|()| "Unable to convert VersionedMultiLocation".as_bytes())?; + let schedule_fee = MultiLocation::try_from(*schedule_fee).map_err(|()| "Unable to convert VersionedMultiLocation".as_bytes())?; + let action = Action::XCMP { destination, schedule_fee, execution_fee: *execution_fee, encoded_call, encoded_call_weight, overall_weight, schedule_as: None, instruction_sequence: InstructionSequence::PayThroughSovereignAccount }; Ok((action, schedule.number_of_executions())) }, RuntimeCall::AutomationTime(pallet_automation_time::Call::schedule_xcmp_task_through_proxy{ - para_id, currency_id, xcm_asset_location, encoded_call, encoded_call_weight, schedule, schedule_as, .. + destination, schedule_fee, execution_fee, encoded_call, encoded_call_weight, overall_weight, schedule, schedule_as, .. }) => { - let action = Action::XCMP { para_id, currency_id, xcm_asset_location, encoded_call, encoded_call_weight, schedule_as: Some(schedule_as) }; + let destination = MultiLocation::try_from(*destination).map_err(|()| "Unable to convert VersionedMultiLocation".as_bytes())?; + let schedule_fee = MultiLocation::try_from(*schedule_fee).map_err(|()| "Unable to convert VersionedMultiLocation".as_bytes())?; + let action = Action::XCMP { destination, schedule_fee, execution_fee: *execution_fee, encoded_call, encoded_call_weight, overall_weight, schedule_as: Some(schedule_as), instruction_sequence: InstructionSequence::PayThroughRemoteDerivativeAccount }; Ok((action, schedule.number_of_executions())) }, RuntimeCall::AutomationTime(pallet_automation_time::Call::schedule_dynamic_dispatch_task{ @@ -1166,15 +1175,15 @@ impl_runtime_apis! { .map_err(|_| "Unable to parse fee".as_bytes())?; Ok(AutomationFeeDetails { - execution_fee: fee_handler.execution_fee.into(), - xcmp_fee: fee_handler.xcmp_fee.into() + schedule_fee: fee_handler.schedule_fee_amount.into(), + execution_fee: fee_handler.execution_fee_amount.into() }) } /** * The get_time_automation_fees RPC function is used to get the execution fee of scheduling a time-automation task. * This function requires the action type and the number of executions in order to generate an estimate. - * However, the AutomationTime::calculate_execution_fee requires an Action enum from the automation time pallet, + * However, the AutomationTime::calculate_schedule_fee_amount requires an Action enum from the automation time pallet, * which requires more information than is necessary for this calculation. * Therefore, for ease of use, this function will just require an integer representing the action type and an integer * representing the number of executions. For all of the extraneous information, the function will provide faux inputs for it. @@ -1184,7 +1193,7 @@ impl_runtime_apis! { action: AutomationAction, executions: u32, ) -> Balance { - AutomationTime::calculate_execution_fee(&(action.into()), executions).expect("Can only fail for DynamicDispatch which is not an option here") + AutomationTime::calculate_schedule_fee_amount(&(action.into()), executions).expect("Can only fail for DynamicDispatch which is not an option here") } fn calculate_optimal_autostaking( @@ -1196,7 +1205,7 @@ impl_runtime_apis! { let collator_stake = candidate_info.ok_or("collator does not exist")?.total_counted as i128; - let fee = AutomationTime::calculate_execution_fee(&(AutomationAction::AutoCompoundDelegatedStake.into()), 1).expect("Can only fail for DynamicDispatch and this is always AutoCompoundDelegatedStake") as i128; + let fee = AutomationTime::calculate_schedule_fee_amount(&(AutomationAction::AutoCompoundDelegatedStake.into()), 1).expect("Can only fail for DynamicDispatch and this is always AutoCompoundDelegatedStake") as i128; let duration = 90; let total_collators = ParachainStaking::total_selected(); @@ -1249,7 +1258,6 @@ impl_runtime_apis! { use pallet_valve::Pallet as Valve; use pallet_vesting::Pallet as Vesting; use pallet_parachain_staking::Pallet as ParachainStaking; - use pallet_xcmp_handler::Pallet as XcmpHandler; let mut list = Vec::::new(); @@ -1257,7 +1265,6 @@ impl_runtime_apis! { list_benchmark!(list, extra, pallet_valve, Valve::); list_benchmark!(list, extra, pallet_vesting, Vesting::); list_benchmark!(list, extra, pallet_parachain_staking, ParachainStaking::); - list_benchmark!(list, extra, pallet_xcmp_handler, XcmpHandler::); let storage_info = AllPalletsWithSystem::storage_info(); @@ -1274,7 +1281,6 @@ impl_runtime_apis! { use pallet_valve::Pallet as Valve; use pallet_vesting::Pallet as Vesting; use pallet_parachain_staking::Pallet as ParachainStaking; - use pallet_xcmp_handler::Pallet as XcmpHandler; let whitelist: Vec = vec![ // Block Number @@ -1296,7 +1302,6 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_valve, Valve::); add_benchmark!(params, batches, pallet_vesting, Vesting::); add_benchmark!(params, batches, pallet_parachain_staking, ParachainStaking::); - add_benchmark!(params, batches, pallet_xcmp_handler, XcmpHandler::); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) diff --git a/runtime/neumann/src/xcm_config.rs b/runtime/neumann/src/xcm_config.rs index 51ade4b0e..dbb6577c1 100644 --- a/runtime/neumann/src/xcm_config.rs +++ b/runtime/neumann/src/xcm_config.rs @@ -1,7 +1,7 @@ use super::{ AccountId, AllPalletsWithSystem, Balance, Balances, Currencies, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TokenId, TreasuryAccount, - UnknownTokens, XcmpQueue, MAXIMUM_BLOCK_WEIGHT, NATIVE_TOKEN_ID, + UniversalLocation, UnknownTokens, XcmpQueue, MAXIMUM_BLOCK_WEIGHT, NATIVE_TOKEN_ID, }; use frame_support::{ @@ -40,9 +40,6 @@ parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); pub const RelayNetwork: NetworkId = NetworkId::Rococo; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - // The universal location within the global consensus system - pub UniversalLocation: InteriorMultiLocation = - X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); } @@ -309,7 +306,6 @@ impl pallet_xcmp_handler::Config for Runtime { type XcmSender = XcmRouter; type XcmExecutor = XcmExecutor; type Weigher = FixedWeightBounds; - type WeightInfo = pallet_xcmp_handler::weights::SubstrateWeight; } pub struct TokenIdConvert; diff --git a/runtime/oak/Cargo.toml b/runtime/oak/Cargo.toml index fc2347b47..a2e5744d1 100644 --- a/runtime/oak/Cargo.toml +++ b/runtime/oak/Cargo.toml @@ -206,7 +206,6 @@ runtime-benchmarks = [ "pallet-valve/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "pallet-xcmp-handler/runtime-benchmarks", "pallet-parachain-staking/runtime-benchmarks", ] diff --git a/runtime/oak/src/lib.rs b/runtime/oak/src/lib.rs index a34a4719c..1cb5451c7 100644 --- a/runtime/oak/src/lib.rs +++ b/runtime/oak/src/lib.rs @@ -104,6 +104,7 @@ use primitives::{ // Custom pallet imports pub use pallet_automation_time; +use pallet_xcmp_handler::InstructionSequence; use primitives::EnsureProxy; @@ -188,6 +189,9 @@ pub fn native_version() -> NativeVersion { parameter_types! { pub const RelayNetwork: NetworkId = NetworkId::Polkadot; + // The universal location within the global consensus system + pub UniversalLocation: InteriorMultiLocation = + X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); } parameter_types! { @@ -903,7 +907,6 @@ impl pallet_automation_time::Config for Runtime { type Currency = Balances; type MultiCurrency = Currencies; type CurrencyId = TokenId; - type GetNativeCurrencyId = GetNativeCurrencyId; type XcmpTransactor = XcmpHandler; type FeeHandler = pallet_automation_time::FeeHandler; type DelegatorActions = ParachainStaking; @@ -912,6 +915,8 @@ impl pallet_automation_time::Config for Runtime { type Call = RuntimeCall; type ScheduleAllowList = ScheduleAllowList; type EnsureProxy = AutomationEnsureProxy; + type UniversalLocation = UniversalLocation; + type SelfParaId = parachain_info::Pallet; } pub struct ClosedCallFilter; @@ -1012,7 +1017,7 @@ construct_runtime!( //custom pallets AutomationTime: pallet_automation_time::{Pallet, Call, Storage, Event} = 60, Vesting: pallet_vesting::{Pallet, Storage, Config, Event} = 61, - XcmpHandler: pallet_xcmp_handler::{Pallet, Call, Storage, Config, Event} = 62, + XcmpHandler: pallet_xcmp_handler::{Pallet, Call, Event} = 62, } ); @@ -1153,15 +1158,19 @@ impl_runtime_apis! { let (action, executions) = match uxt.function { RuntimeCall::AutomationTime(pallet_automation_time::Call::schedule_xcmp_task{ - para_id, currency_id, xcm_asset_location, encoded_call, encoded_call_weight, schedule, .. + destination, schedule_fee, execution_fee, encoded_call, encoded_call_weight, overall_weight, schedule, .. }) => { - let action = Action::XCMP { para_id, currency_id, xcm_asset_location, encoded_call, encoded_call_weight, schedule_as:None }; + let destination = MultiLocation::try_from(*destination).map_err(|()| "Unable to convert VersionedMultiLocation".as_bytes())?; + let schedule_fee = MultiLocation::try_from(*schedule_fee).map_err(|()| "Unable to convert VersionedMultiLocation".as_bytes())?; + let action = Action::XCMP { destination, schedule_fee, execution_fee: *execution_fee, encoded_call, encoded_call_weight, overall_weight, schedule_as: None, instruction_sequence: InstructionSequence::PayThroughSovereignAccount }; Ok((action, schedule.number_of_executions())) }, RuntimeCall::AutomationTime(pallet_automation_time::Call::schedule_xcmp_task_through_proxy{ - para_id, currency_id, xcm_asset_location, encoded_call, encoded_call_weight, schedule, schedule_as, .. + destination, schedule_fee, execution_fee, encoded_call, encoded_call_weight, overall_weight, schedule, schedule_as, .. }) => { - let action = Action::XCMP { para_id, currency_id, xcm_asset_location, encoded_call, encoded_call_weight, schedule_as: Some(schedule_as) }; + let destination = MultiLocation::try_from(*destination).map_err(|()| "Unable to convert VersionedMultiLocation".as_bytes())?; + let schedule_fee = MultiLocation::try_from(*schedule_fee).map_err(|()| "Unable to convert VersionedMultiLocation".as_bytes())?; + let action = Action::XCMP { destination, schedule_fee, execution_fee: *execution_fee, encoded_call, encoded_call_weight, overall_weight, schedule_as: Some(schedule_as), instruction_sequence: InstructionSequence::PayThroughRemoteDerivativeAccount }; Ok((action, schedule.number_of_executions())) }, RuntimeCall::AutomationTime(pallet_automation_time::Call::schedule_dynamic_dispatch_task{ @@ -1178,15 +1187,15 @@ impl_runtime_apis! { .map_err(|_| "Unable to parse fee".as_bytes())?; Ok(AutomationFeeDetails { - execution_fee: fee_handler.execution_fee.into(), - xcmp_fee: fee_handler.xcmp_fee.into() + schedule_fee: fee_handler.schedule_fee_amount.into(), + execution_fee: fee_handler.execution_fee_amount.into() }) } /** * The get_time_automation_fees RPC function is used to get the execution fee of scheduling a time-automation task. * This function requires the action type and the number of executions in order to generate an estimate. - * However, the AutomationTime::calculate_execution_fee requires an Action enum from the automation time pallet, + * However, the AutomationTime::calculate_schedule_fee_amount requires an Action enum from the automation time pallet, * which requires more information than is necessary for this calculation. * Therefore, for ease of use, this function will just require an integer representing the action type and an integer * representing the number of executions. For all of the extraneous information, the function will provide faux inputs for it. @@ -1196,7 +1205,7 @@ impl_runtime_apis! { action: AutomationAction, executions: u32, ) -> Balance { - AutomationTime::calculate_execution_fee(&(action.into()), executions).expect("Can only fail for DynamicDispatch which is not an option here") + AutomationTime::calculate_schedule_fee_amount(&(action.into()), executions).expect("Can only fail for DynamicDispatch which is not an option here") } fn calculate_optimal_autostaking( @@ -1208,7 +1217,7 @@ impl_runtime_apis! { let collator_stake = candidate_info.ok_or("collator does not exist")?.total_counted as i128; - let fee = AutomationTime::calculate_execution_fee(&(AutomationAction::AutoCompoundDelegatedStake.into()), 1).expect("Can only fail for DynamicDispatch and this is always AutoCompoundDelegatedStake") as i128; + let fee = AutomationTime::calculate_schedule_fee_amount(&(AutomationAction::AutoCompoundDelegatedStake.into()), 1).expect("Can only fail for DynamicDispatch and this is always AutoCompoundDelegatedStake") as i128; let duration = 90; let total_collators = ParachainStaking::total_selected(); @@ -1285,7 +1294,6 @@ impl_runtime_apis! { use pallet_valve::Pallet as Valve; use pallet_vesting::Pallet as Vesting; use pallet_parachain_staking::Pallet as ParachainStaking; - use pallet_xcmp_handler::Pallet as XcmpHandler; let mut list = Vec::::new(); @@ -1293,7 +1301,6 @@ impl_runtime_apis! { list_benchmark!(list, extra, pallet_valve, Valve::); list_benchmark!(list, extra, pallet_vesting, Vesting::); list_benchmark!(list, extra, pallet_parachain_staking, ParachainStaking::); - list_benchmark!(list, extra, pallet_xcmp_handler, XcmpHandler::); let storage_info = AllPalletsWithSystem::storage_info(); @@ -1310,7 +1317,6 @@ impl_runtime_apis! { use pallet_valve::Pallet as Valve; use pallet_vesting::Pallet as Vesting; use pallet_parachain_staking::Pallet as ParachainStaking; - use pallet_xcmp_handler::Pallet as XcmpHandler; let whitelist: Vec = vec![ // Block Number @@ -1332,7 +1338,6 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_valve, Valve::); add_benchmark!(params, batches, pallet_vesting, Vesting::); add_benchmark!(params, batches, pallet_parachain_staking, ParachainStaking::); - add_benchmark!(params, batches, pallet_xcmp_handler, XcmpHandler::); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) diff --git a/runtime/oak/src/xcm_config.rs b/runtime/oak/src/xcm_config.rs index 3df25952c..bd83c3146 100644 --- a/runtime/oak/src/xcm_config.rs +++ b/runtime/oak/src/xcm_config.rs @@ -1,8 +1,8 @@ use super::{ AccountId, AllPalletsWithSystem, Balance, Balances, Currencies, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TemporaryForeignTreasuryAccount, TokenId, TreasuryAccount, UnknownTokens, XcmpQueue, - MAXIMUM_BLOCK_WEIGHT, NATIVE_TOKEN_ID, + TemporaryForeignTreasuryAccount, TokenId, TreasuryAccount, UniversalLocation, UnknownTokens, + XcmpQueue, MAXIMUM_BLOCK_WEIGHT, NATIVE_TOKEN_ID, }; use frame_support::{ @@ -42,9 +42,6 @@ parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); pub const RelayNetwork: NetworkId = NetworkId::Polkadot; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - // The universal location within the global consensus system - pub UniversalLocation: InteriorMultiLocation = - X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); } @@ -313,7 +310,6 @@ impl pallet_xcmp_handler::Config for Runtime { type XcmSender = XcmRouter; type XcmExecutor = XcmExecutor; type Weigher = FixedWeightBounds; - type WeightInfo = pallet_xcmp_handler::weights::SubstrateWeight; } pub struct TokenIdConvert; diff --git a/runtime/turing/Cargo.toml b/runtime/turing/Cargo.toml index 3232dcd4b..fa3bdeb96 100644 --- a/runtime/turing/Cargo.toml +++ b/runtime/turing/Cargo.toml @@ -206,7 +206,6 @@ runtime-benchmarks = [ "pallet-valve/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "pallet-xcmp-handler/runtime-benchmarks", "pallet-parachain-staking/runtime-benchmarks", ] diff --git a/runtime/turing/src/lib.rs b/runtime/turing/src/lib.rs index 894c1fd2f..621ae63f7 100644 --- a/runtime/turing/src/lib.rs +++ b/runtime/turing/src/lib.rs @@ -103,6 +103,7 @@ use primitives::{ // Custom pallet imports pub use pallet_automation_price; pub use pallet_automation_time; +use pallet_xcmp_handler::InstructionSequence; use primitives::EnsureProxy; @@ -145,7 +146,7 @@ pub type Executive = frame_executive::Executive< // All migrations executed on runtime upgrade as a nested tuple of types implementing // `OnRuntimeUpgrade`. -type Migrations = (); +type Migrations = (pallet_automation_time::migrations::update_xcmp_task::UpdateXcmpTask,); /// Opaque types. These are used by the CLI to instantiate machinery that don't need to know /// the specifics of the runtime. They can then be made to be agnostic over specific formats @@ -192,6 +193,9 @@ pub fn native_version() -> NativeVersion { parameter_types! { pub const RelayNetwork: NetworkId = NetworkId::Kusama; + // The universal location within the global consensus system + pub UniversalLocation: InteriorMultiLocation = + X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); } parameter_types! { @@ -902,7 +906,6 @@ impl pallet_automation_time::Config for Runtime { type Currency = Balances; type MultiCurrency = Currencies; type CurrencyId = TokenId; - type GetNativeCurrencyId = GetNativeCurrencyId; type XcmpTransactor = XcmpHandler; type FeeHandler = pallet_automation_time::FeeHandler; type DelegatorActions = ParachainStaking; @@ -911,6 +914,8 @@ impl pallet_automation_time::Config for Runtime { type Call = RuntimeCall; type ScheduleAllowList = ScheduleAllowList; type EnsureProxy = AutomationEnsureProxy; + type UniversalLocation = UniversalLocation; + type SelfParaId = parachain_info::Pallet; } impl pallet_automation_price::Config for Runtime { @@ -1023,7 +1028,7 @@ construct_runtime!( //custom pallets AutomationTime: pallet_automation_time::{Pallet, Call, Storage, Event} = 60, Vesting: pallet_vesting::{Pallet, Storage, Config, Event} = 61, - XcmpHandler: pallet_xcmp_handler::{Pallet, Call, Storage, Config, Event} = 62, + XcmpHandler: pallet_xcmp_handler::{Pallet, Call, Event} = 62, AutomationPrice: pallet_automation_price::{Pallet, Call, Storage, Event} = 200, } ); @@ -1165,15 +1170,19 @@ impl_runtime_apis! { let (action, executions) = match uxt.function { RuntimeCall::AutomationTime(pallet_automation_time::Call::schedule_xcmp_task{ - para_id, currency_id, xcm_asset_location, encoded_call, encoded_call_weight, schedule, .. + destination, schedule_fee, execution_fee, encoded_call, encoded_call_weight, overall_weight, schedule, .. }) => { - let action = Action::XCMP { para_id, currency_id, xcm_asset_location, encoded_call, encoded_call_weight, schedule_as: None }; + let destination = MultiLocation::try_from(*destination).map_err(|()| "Unable to convert VersionedMultiLocation".as_bytes())?; + let schedule_fee = MultiLocation::try_from(*schedule_fee).map_err(|()| "Unable to convert VersionedMultiLocation".as_bytes())?; + let action = Action::XCMP { destination, schedule_fee, execution_fee: *execution_fee, encoded_call, encoded_call_weight, overall_weight, schedule_as: None, instruction_sequence: InstructionSequence::PayThroughSovereignAccount }; Ok((action, schedule.number_of_executions())) }, RuntimeCall::AutomationTime(pallet_automation_time::Call::schedule_xcmp_task_through_proxy{ - para_id, currency_id, xcm_asset_location, encoded_call, encoded_call_weight, schedule, schedule_as, .. + destination, schedule_fee, execution_fee, encoded_call, encoded_call_weight, overall_weight, schedule, schedule_as, .. }) => { - let action = Action::XCMP { para_id, currency_id, xcm_asset_location, encoded_call, encoded_call_weight, schedule_as: Some(schedule_as) }; + let destination = MultiLocation::try_from(*destination).map_err(|()| "Unable to convert VersionedMultiLocation".as_bytes())?; + let schedule_fee = MultiLocation::try_from(*schedule_fee).map_err(|()| "Unable to convert VersionedMultiLocation".as_bytes())?; + let action = Action::XCMP { destination, schedule_fee, execution_fee: *execution_fee, encoded_call, encoded_call_weight, overall_weight, schedule_as: Some(schedule_as), instruction_sequence: InstructionSequence::PayThroughRemoteDerivativeAccount }; Ok((action, schedule.number_of_executions())) }, RuntimeCall::AutomationTime(pallet_automation_time::Call::schedule_dynamic_dispatch_task{ @@ -1189,16 +1198,18 @@ impl_runtime_apis! { let fee_handler = ::FeeHandler::new(&nobody, &action, executions) .map_err(|_| "Unable to parse fee".as_bytes())?; + log::error!("fee_handler.schedule_fee_amount: {:?}", fee_handler.schedule_fee_amount); + log::error!("fee_handler.execution_fee_amount: {:?}", fee_handler.execution_fee_amount); Ok(AutomationFeeDetails { - execution_fee: fee_handler.execution_fee.into(), - xcmp_fee: fee_handler.xcmp_fee.into() + schedule_fee: fee_handler.schedule_fee_amount.into(), + execution_fee: fee_handler.execution_fee_amount.into() }) } /** * The get_time_automation_fees RPC function is used to get the execution fee of scheduling a time-automation task. * This function requires the action type and the number of executions in order to generate an estimate. - * However, the AutomationTime::calculate_execution_fee requires an Action enum from the automation time pallet, + * However, the AutomationTime::calculate_schedule_fee_amount requires an Action enum from the automation time pallet, * which requires more information than is necessary for this calculation. * Therefore, for ease of use, this function will just require an integer representing the action type and an integer * representing the number of executions. For all of the extraneous information, the function will provide faux inputs for it. @@ -1208,7 +1219,7 @@ impl_runtime_apis! { action: AutomationAction, executions: u32, ) -> Balance { - AutomationTime::calculate_execution_fee(&(action.into()), executions).expect("Can only fail for DynamicDispatch which is not an option here") + AutomationTime::calculate_schedule_fee_amount(&(action.into()), executions).expect("Can only fail for DynamicDispatch which is not an option here") } fn calculate_optimal_autostaking( @@ -1220,7 +1231,7 @@ impl_runtime_apis! { let collator_stake = candidate_info.ok_or("collator does not exist")?.total_counted as i128; - let fee = AutomationTime::calculate_execution_fee(&(AutomationAction::AutoCompoundDelegatedStake.into()), 1).expect("Can only fail for DynamicDispatch and this is always AutoCompoundDelegatedStake") as i128; + let fee = AutomationTime::calculate_schedule_fee_amount(&(AutomationAction::AutoCompoundDelegatedStake.into()), 1).expect("Can only fail for DynamicDispatch and this is always AutoCompoundDelegatedStake") as i128; let duration = 90; let total_collators = ParachainStaking::total_selected(); @@ -1297,7 +1308,6 @@ impl_runtime_apis! { use pallet_valve::Pallet as Valve; use pallet_vesting::Pallet as Vesting; use pallet_parachain_staking::Pallet as ParachainStaking; - use pallet_xcmp_handler::Pallet as XcmpHandler; let mut list = Vec::::new(); @@ -1305,7 +1315,6 @@ impl_runtime_apis! { list_benchmark!(list, extra, pallet_valve, Valve::); list_benchmark!(list, extra, pallet_vesting, Vesting::); list_benchmark!(list, extra, pallet_parachain_staking, ParachainStaking::); - list_benchmark!(list, extra, pallet_xcmp_handler, XcmpHandler::); let storage_info = AllPalletsWithSystem::storage_info(); @@ -1322,7 +1331,6 @@ impl_runtime_apis! { use pallet_valve::Pallet as Valve; use pallet_vesting::Pallet as Vesting; use pallet_parachain_staking::Pallet as ParachainStaking; - use pallet_xcmp_handler::Pallet as XcmpHandler; let whitelist: Vec = vec![ // Block Number @@ -1344,7 +1352,6 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_valve, Valve::); add_benchmark!(params, batches, pallet_vesting, Vesting::); add_benchmark!(params, batches, pallet_parachain_staking, ParachainStaking::); - add_benchmark!(params, batches, pallet_xcmp_handler, XcmpHandler::); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) diff --git a/runtime/turing/src/xcm_config.rs b/runtime/turing/src/xcm_config.rs index 0c605ab27..a0d45fd33 100644 --- a/runtime/turing/src/xcm_config.rs +++ b/runtime/turing/src/xcm_config.rs @@ -1,8 +1,8 @@ use super::{ AccountId, AllPalletsWithSystem, Balance, Balances, Currencies, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TemporaryForeignTreasuryAccount, TokenId, TreasuryAccount, UnknownTokens, XcmpQueue, - MAXIMUM_BLOCK_WEIGHT, NATIVE_TOKEN_ID, + TemporaryForeignTreasuryAccount, TokenId, TreasuryAccount, UniversalLocation, UnknownTokens, + XcmpQueue, MAXIMUM_BLOCK_WEIGHT, NATIVE_TOKEN_ID, }; use frame_support::{ @@ -41,9 +41,6 @@ parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); pub const RelayNetwork: NetworkId = NetworkId::Kusama; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - // The universal location within the global consensus system - pub UniversalLocation: InteriorMultiLocation = - X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); } @@ -312,7 +309,6 @@ impl pallet_xcmp_handler::Config for Runtime { type XcmSender = XcmRouter; type XcmExecutor = XcmExecutor; type Weigher = FixedWeightBounds; - type WeightInfo = pallet_xcmp_handler::weights::SubstrateWeight; } pub struct TokenIdConvert;