diff --git a/generic-template/Cargo.lock b/generic-template/Cargo.lock index 7065c1b..1daa7a2 100644 --- a/generic-template/Cargo.lock +++ b/generic-template/Cargo.lock @@ -3660,6 +3660,7 @@ dependencies = [ "pallet-utility", "pallet-whitelist", "pallet-xcm", + "pallet-xcm-transactor", "pallet-xcm-weight-trader", "parachains-common", "parity-scale-codec", @@ -7591,6 +7592,29 @@ dependencies = [ "staging-xcm-executor", ] +[[package]] +name = "pallet-xcm-transactor" +version = "0.2.0" +source = "git+https://github.com/OpenZeppelin/moonbeam.git?branch=polkadot-stable2407-1#fab6e72fbaaeaa065ad983556d09d4c0e8755dfa" +dependencies = [ + "cumulus-primitives-core", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "orml-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "xcm-primitives", +] + [[package]] name = "pallet-xcm-weight-trader" version = "0.1.0" diff --git a/generic-template/Cargo.toml b/generic-template/Cargo.toml index 304b3a5..21645ce 100644 --- a/generic-template/Cargo.toml +++ b/generic-template/Cargo.toml @@ -132,6 +132,7 @@ parachains-common = { git = "https://github.com/paritytech/polkadot-sdk", defaul # Moonbeam pallet-asset-manager = { git = "https://github.com/OpenZeppelin/moonbeam.git", branch = "polkadot-stable2407-1", default-features = false } +pallet-xcm-transactor = { git = "https://github.com/OpenZeppelin/moonbeam.git", branch = "polkadot-stable2407-1", default-features = false } pallet-xcm-weight-trader = { git = "https://github.com/OpenZeppelin/moonbeam.git", branch = "polkadot-stable2407-1", default-features = false } xcm-primitives = { git = "https://github.com/OpenZeppelin/moonbeam.git", branch = "polkadot-stable2407-1", default-features = false } diff --git a/generic-template/runtime/Cargo.toml b/generic-template/runtime/Cargo.toml index 9a12a30..f7fe344 100644 --- a/generic-template/runtime/Cargo.toml +++ b/generic-template/runtime/Cargo.toml @@ -84,6 +84,7 @@ parachains-common = { workspace = true } # Moonbeam pallet-asset-manager = { workspace = true } +pallet-xcm-transactor = { workspace = true } pallet-xcm-weight-trader = { workspace = true } xcm-primitives = { workspace = true } @@ -141,6 +142,7 @@ std = [ "pallet-treasury/std", "pallet-utility/std", "pallet-whitelist/std", + "pallet-xcm-transactor/std", "pallet-xcm-weight-trader/std", "pallet-xcm/std", "parachain-info/std", @@ -195,6 +197,7 @@ runtime-benchmarks = [ "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-whitelist/runtime-benchmarks", + "pallet-xcm-transactor/runtime-benchmarks", "pallet-xcm-weight-trader/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", @@ -236,6 +239,7 @@ try-runtime = [ "pallet-treasury/try-runtime", "pallet-utility/try-runtime", "pallet-whitelist/try-runtime", + "pallet-xcm-transactor/try-runtime", "pallet-xcm-weight-trader/try-runtime", "pallet-xcm/try-runtime", "parachain-info/try-runtime", diff --git a/generic-template/runtime/src/benchmark.rs b/generic-template/runtime/src/benchmark.rs index 308dd46..6afbc55 100644 --- a/generic-template/runtime/src/benchmark.rs +++ b/generic-template/runtime/src/benchmark.rs @@ -19,6 +19,7 @@ frame_benchmarking::define_benchmarks!( [pallet_treasury, Treasury] [pallet_conviction_voting, ConvictionVoting] [pallet_whitelist, Whitelist] + [pallet_xcm_transactor, XcmTransactor] ); use cumulus_primitives_core::{ChannelStatus, GetChannelInfo}; diff --git a/generic-template/runtime/src/configs/asset_config.rs b/generic-template/runtime/src/configs/asset_config.rs index 3b8c1d2..e71c707 100644 --- a/generic-template/runtime/src/configs/asset_config.rs +++ b/generic-template/runtime/src/configs/asset_config.rs @@ -28,6 +28,19 @@ parameter_types! { pub const RemoveItemsLimit: u32 = 1000; } +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u32).into() + } + } +} + // Foreign assets impl pallet_assets::Config for Runtime { type ApprovalDeposit = ApprovalDeposit; @@ -37,7 +50,7 @@ impl pallet_assets::Config for Runtime { type AssetIdParameter = Compact; type Balance = Balance; #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); + type BenchmarkHelper = BenchmarkHelper; type CallbackHandle = (); type CreateOrigin = AsEnsureOriginWithArg>; type Currency = Balances; diff --git a/generic-template/runtime/src/configs/xcm_config.rs b/generic-template/runtime/src/configs/xcm_config.rs index d201b80..6d480ba 100644 --- a/generic-template/runtime/src/configs/xcm_config.rs +++ b/generic-template/runtime/src/configs/xcm_config.rs @@ -13,7 +13,7 @@ use pallet_xcm::XcmPassthrough; use parity_scale_codec::{Decode, Encode}; use polkadot_parachain_primitives::primitives::{self, Sibling}; use scale_info::TypeInfo; -use sp_runtime::traits::Convert; +use sp_runtime::{traits::Convert, Vec}; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, Case, @@ -25,7 +25,9 @@ use xcm_builder::{ WithUniqueTopic, XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::XcmExecutor; -use xcm_primitives::{AbsoluteAndRelativeReserve, AsAssetType}; +use xcm_primitives::{ + AbsoluteAndRelativeReserve, AsAssetType, UtilityAvailableCalls, UtilityEncodeCall, XcmTransact, +}; use super::TreasuryAccount; use crate::{ @@ -489,3 +491,114 @@ impl pallet_xcm_weight_trader::Config for Runtime { type WeightToFee = ::WeightToFee; type XcmFeesAccount = TreasuryAccount; } + +// For now we only allow to transact in the relay, although this might change in the future +// Transactors just defines the chains in which we allow transactions to be issued through +// xcm +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum Transactors { + Relay, +} + +// Default for benchmarking +#[cfg(feature = "runtime-benchmarks")] +impl Default for Transactors { + fn default() -> Self { + Transactors::Relay + } +} + +impl TryFrom for Transactors { + type Error = (); + + fn try_from(value: u8) -> Result { + match value { + 0u8 => Ok(Transactors::Relay), + _ => Err(()), + } + } +} + +impl UtilityEncodeCall for Transactors { + fn encode_call(self, call: UtilityAvailableCalls) -> Vec { + match self { + Transactors::Relay => pallet_xcm_transactor::Pallet::::encode_call( + pallet_xcm_transactor::Pallet(sp_std::marker::PhantomData::), + call, + ), + } + } +} + +impl XcmTransact for Transactors { + fn destination(self) -> Location { + match self { + Transactors::Relay => Location::parent(), + } + } +} + +parameter_types! { + pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into(); +} + +// implement your own business logic for who can manage and use xcm-transactor +pub type DerivativeAddressRegistrationOrigin = EnsureRoot; +pub type HrmpManipulatorOrigin = EnsureRoot; +pub type HrmpOpenOrigin = EnsureRoot; +pub type SovereignAccountDispatcherOrigin = EnsureRoot; + +impl pallet_xcm_transactor::Config for Runtime { + type AccountIdToLocation = AccountIdToLocation; + type AssetTransactor = AssetTransactors; + type Balance = Balance; + type BaseXcmWeight = BaseXcmWeight; + type CurrencyId = CurrencyId; + type CurrencyIdToLocation = CurrencyIdToLocation>; + type DerivativeAddressRegistrationOrigin = DerivativeAddressRegistrationOrigin; + type HrmpManipulatorOrigin = HrmpManipulatorOrigin; + type HrmpOpenOrigin = HrmpOpenOrigin; + type MaxHrmpFee = xcm_builder::Case; + type ReserveProvider = AbsoluteAndRelativeReserve; + type RuntimeEvent = RuntimeEvent; + type SelfLocation = SelfLocation; + type SovereignAccountDispatcherOrigin = SovereignAccountDispatcherOrigin; + type Transactor = Transactors; + type UniversalLocation = UniversalLocation; + type Weigher = XcmWeigher; + type WeightInfo = weights::pallet_xcm_transactor::WeightInfo; + type XcmSender = XcmRouter; +} + +#[cfg(feature = "runtime-benchmarks")] +mod testing { + use sp_runtime::traits::MaybeEquivalence; + use xcm_builder::WithLatestLocationConverter; + use xcm_executor::traits::ConvertLocation; + + use super::*; + + /// This From exists for benchmarking purposes. It has the potential side-effect of calling + /// AssetManager::set_asset_type_asset_id() and should NOT be used in any production code. + impl From for CurrencyId { + fn from(location: Location) -> CurrencyId { + use xcm_primitives::AssetTypeGetter; + + // If it does not exist, for benchmarking purposes, we create the association + let asset_id = if let Some(asset_id) = + AsAssetType::::convert_location(&location) + { + asset_id + } else { + let asset_type = AssetType::Xcm( + WithLatestLocationConverter::convert(&location).expect("convert to v3"), + ); + let asset_id: AssetId = asset_type.clone().into(); + AssetManager::set_asset_type_asset_id(asset_type, asset_id); + asset_id + }; + + CurrencyId::ForeignAsset(asset_id) + } + } +} diff --git a/generic-template/runtime/src/lib.rs b/generic-template/runtime/src/lib.rs index 5b9fed5..8b93614 100644 --- a/generic-template/runtime/src/lib.rs +++ b/generic-template/runtime/src/lib.rs @@ -189,6 +189,8 @@ mod runtime { pub type XTokens = orml_xtokens; #[runtime::pallet_index(35)] pub type XcmWeightTrader = pallet_xcm_weight_trader; + #[runtime::pallet_index(36)] + pub type XcmTransactor = pallet_xcm_transactor; } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/generic-template/runtime/src/weights/mod.rs b/generic-template/runtime/src/weights/mod.rs index 22bd7d5..693234c 100644 --- a/generic-template/runtime/src/weights/mod.rs +++ b/generic-template/runtime/src/weights/mod.rs @@ -39,6 +39,7 @@ pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_whitelist; pub mod pallet_xcm; +pub mod pallet_xcm_transactor; pub mod pallet_xcm_weight_trader; pub mod paritydb_weights; pub mod rocksdb_weights; diff --git a/generic-template/runtime/src/weights/pallet_xcm_transactor.rs b/generic-template/runtime/src/weights/pallet_xcm_transactor.rs new file mode 100644 index 0000000..a5053b6 --- /dev/null +++ b/generic-template/runtime/src/weights/pallet_xcm_transactor.rs @@ -0,0 +1,177 @@ + +//! Autogenerated weights for `pallet_whitelist` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-172-31-15-118`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 + +// Executed Command: +// target/release/parachain-template-node +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=benchmarking/results/results-pallet_whitelist.json +// --pallet=pallet_whitelist +// --chain=dev +// --output=benchmarking/new-benchmarks/pallet_whitelist.rs + +#![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; + +/// Weights for `pallet_xcm_transactor`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_transactor::WeightInfo for WeightInfo { + /// Storage: `XcmTransactor::IndexToAccount` (r:1 w:1) + /// Proof: `XcmTransactor::IndexToAccount` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn register() -> Weight { + // Proof Size summary in bytes: + // Measured: `114` + // Estimated: `3579` + // Minimum execution time: 9_597_000 picoseconds. + Weight::from_parts(9_924_000, 3579) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::IndexToAccount` (r:0 w:1) + /// Proof: `XcmTransactor::IndexToAccount` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn deregister() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_707_000 picoseconds. + Weight::from_parts(5_973_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:0 w:1) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn set_transact_info() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_118_000 picoseconds. + Weight::from_parts(7_356_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:0 w:1) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_transact_info() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_362_000 picoseconds. + Weight::from_parts(6_609_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:0 w:1) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn set_fee_per_second() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_443_000 picoseconds. + Weight::from_parts(6_670_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::IndexToAccount` (r:1 w:0) + /// Proof: `XcmTransactor::IndexToAccount` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::RelayIndices` (r:1 w:0) + /// Proof: `XcmTransactor::RelayIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeId` (r:1 w:0) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn transact_through_derivative() -> Weight { + // Proof Size summary in bytes: + // Measured: `489` + // Estimated: `3954` + // Minimum execution time: 30_458_000 picoseconds. + Weight::from_parts(31_176_000, 3954) + .saturating_add(T::DbWeight::get().reads(7_u64)) + } + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeId` (r:1 w:0) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn transact_through_sovereign() -> Weight { + // Proof Size summary in bytes: + // Measured: `423` + // Estimated: `3888` + // Minimum execution time: 22_713_000 picoseconds. + Weight::from_parts(23_258_000, 3888) + .saturating_add(T::DbWeight::get().reads(5_u64)) + } + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn transact_through_signed() -> Weight { + // Proof Size summary in bytes: + // Measured: `467` + // Estimated: `3932` + // Minimum execution time: 38_097_000 picoseconds. + Weight::from_parts(38_892_000, 3932) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `XcmTransactor::RelayIndices` (r:1 w:0) + /// Proof: `XcmTransactor::RelayIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn hrmp_manage() -> Weight { + // Proof Size summary in bytes: + // Measured: `471` + // Estimated: `3936` + // Minimum execution time: 40_918_000 picoseconds. + Weight::from_parts(42_238_000, 3936) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } +} diff --git a/generic-template/template-fuzzer/src/main.rs b/generic-template/template-fuzzer/src/main.rs index e3a5631..af68787 100644 --- a/generic-template/template-fuzzer/src/main.rs +++ b/generic-template/template-fuzzer/src/main.rs @@ -60,6 +60,7 @@ fn generate_genesis(accounts: &[AccountId]) -> Storage { transaction_payment: Default::default(), sudo: SudoConfig { key: Some(root) }, treasury: Default::default(), + ..Default::default() } .build_storage() .unwrap()