// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Polkadot is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{ConstU32, Everything, Nothing}, weights::Weight, }; use frame_system::EnsureRoot; use parity_scale_codec::Encode; use primitive_types::H256; use sp_runtime::{traits::IdentityLookup, AccountId32, BuildStorage}; use sp_std::cell::RefCell; use polkadot_parachain_primitives::primitives::Id as ParaId; use polkadot_runtime_parachains::{configuration, origin, shared}; use xcm::latest::{opaque, prelude::*}; use xcm_executor::XcmExecutor; use staging_xcm_builder as xcm_builder; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, EnsureDecodableXcm, FixedRateOfFungible, FixedWeightBounds, FungibleAdapter, IsChildSystemParachain, IsConcrete, MintLocation, RespectSuspension, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, }; pub type AccountId = AccountId32; pub type Balance = u128; thread_local! { pub static SENT_XCM: RefCell> = RefCell::new(Vec::new()); } pub fn sent_xcm() -> Vec<(Location, opaque::Xcm, XcmHash)> { SENT_XCM.with(|q| (*q.borrow()).clone()) } pub struct TestSendXcm; impl SendXcm for TestSendXcm { type Ticket = (Location, Xcm<()>, XcmHash); fn validate( dest: &mut Option, msg: &mut Option>, ) -> SendResult<(Location, Xcm<()>, XcmHash)> { let msg = msg.take().unwrap(); let hash = fake_message_hash(&msg); let triplet = (dest.take().unwrap(), msg, hash); Ok((triplet, Assets::new())) } fn deliver(triplet: (Location, Xcm<()>, XcmHash)) -> Result { let hash = triplet.2; SENT_XCM.with(|q| q.borrow_mut().push(triplet)); Ok(hash) } } pub type TestXcmRouter = EnsureDecodableXcm; // copied from kusama constants pub const UNITS: Balance = 1_000_000_000_000; pub const CENTS: Balance = UNITS / 30_000; parameter_types! { pub const BlockHashCount: u64 = 250; } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Nonce = u64; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Block = Block; type RuntimeEvent = RuntimeEvent; type BlockHashCount = BlockHashCount; type BlockWeights = (); type BlockLength = (); type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); type DbWeight = (); type BaseCallFilter = Everything; type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub ExistentialDeposit: Balance = 1 * CENTS; pub const MaxLocks: u32 = 50; pub const MaxReserves: u32 = 50; } impl pallet_balances::Config for Runtime { type MaxLocks = MaxLocks; type Balance = Balance; type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; } impl shared::Config for Runtime { type DisabledValidators = (); } impl configuration::Config for Runtime { type WeightInfo = configuration::TestWeightInfo; } // aims to closely emulate the Kusama XcmConfig parameter_types! { pub const KsmLocation: Location = Location::here(); pub const KusamaNetwork: NetworkId = NetworkId::Kusama; pub UniversalLocation: InteriorLocation = KusamaNetwork::get().into(); pub CheckAccount: (AccountId, MintLocation) = (XcmPallet::check_account(), MintLocation::Local); } pub type SovereignAccountOf = (ChildParachainConvertsVia, AccountId32Aliases); pub type LocalCurrencyAdapter = FungibleAdapter, SovereignAccountOf, AccountId, CheckAccount>; pub type LocalAssetTransactor = (LocalCurrencyAdapter,); type LocalOriginConverter = ( SovereignSignedViaLocation, ChildParachainAsNative, SignedAccountId32AsNative, ChildSystemParachainAsSuperuser, ); parameter_types! { pub const BaseXcmWeight: Weight = Weight::from_parts(1_000_000_000, 1024); pub KsmPerSecondPerByte: (AssetId, u128, u128) = (KsmLocation::get().into(), 1, 1); } pub type Barrier = ( TakeWeightCredit, AllowTopLevelPaidExecutionFrom, // Unused/Untested AllowUnpaidExecutionFrom>, ); parameter_types! { pub KusamaForAssetHub: (AssetFilter, Location) = (Wild(AllOf { id: AssetId(Here.into()), fun: WildFungible }), Parachain(1000).into()); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 4; } pub type TrustedTeleporters = (xcm_builder::Case,); pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = TestXcmRouter; type AssetTransactor = LocalAssetTransactor; type OriginConverter = LocalOriginConverter; type IsReserve = (); type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = RespectSuspension; type Weigher = FixedWeightBounds; type Trader = FixedRateOfFungible; type ResponseHandler = XcmPallet; type AssetTrap = XcmPallet; type AssetLocker = (); type AssetExchanger = (); type AssetClaims = XcmPallet; type SubscriptionService = XcmPallet; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type FeeManager = (); type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = (); type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); } pub type LocalOriginToLocation = SignedToAccountId32; impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type UniversalLocation = UniversalLocation; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmRouter = TestXcmRouter; // Anyone can execute XCM messages locally... type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmExecuteFilter = Nothing; type XcmExecutor = XcmExecutor; type XcmTeleportFilter = Everything; type XcmReserveTransferFilter = Everything; type Weigher = FixedWeightBounds; type RuntimeCall = RuntimeCall; type RuntimeOrigin = RuntimeOrigin; const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; type TrustedLockers = (); type SovereignAccountOf = (); type Currency = Balances; type CurrencyMatcher = IsConcrete; type MaxLockers = frame_support::traits::ConstU32<8>; type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; } impl origin::Config for Runtime {} type Block = frame_system::mocking::MockBlock; construct_runtime!( pub enum Runtime { System: frame_system, Balances: pallet_balances, ParasOrigin: origin, XcmPallet: pallet_xcm, } ); pub fn kusama_like_with_balances(balances: Vec<(AccountId, Balance)>) -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); pallet_balances::GenesisConfig:: { balances } .assimilate_storage(&mut t) .unwrap(); let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| System::set_block_number(1)); ext } pub fn fake_message_hash(message: &Xcm) -> XcmHash { message.using_encoded(sp_io::hashing::blake2_256) }