1
// Copyright 2019-2022 PureStake Inc.
2
// This file is part of Moonbeam.
3

            
4
// Moonbeam is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Moonbeam is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
//! XCM configuration for Moonbase.
18
//!
19

            
20
use super::{
21
	governance, AccountId, AssetId, AssetManager, Balance, Balances, DealWithFees, Erc20XcmBridge,
22
	MaintenanceMode, MessageQueue, ParachainInfo, ParachainSystem, Perbill, PolkadotXcm, Runtime,
23
	RuntimeBlockWeights, RuntimeCall, RuntimeEvent, RuntimeOrigin, Treasury, XcmpQueue,
24
};
25

            
26
use frame_support::{
27
	parameter_types,
28
	traits::{EitherOfDiverse, Everything, Nothing, PalletInfoAccess, TransformOrigin},
29
};
30
use moonbeam_runtime_common::weights as moonbeam_weights;
31
use moonkit_xcm_primitives::AccountIdAssetIdConversion;
32
use sp_runtime::{
33
	traits::{Hash as THash, MaybeEquivalence, PostDispatchInfoOf},
34
	DispatchErrorWithPostInfo,
35
};
36
use sp_weights::Weight;
37

            
38
use frame_system::{EnsureRoot, RawOrigin};
39
use sp_core::{ConstU32, H160, H256};
40

            
41
use xcm_builder::{
42
	AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
43
	AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, DescribeAllTerminal, DescribeFamily,
44
	EnsureXcmOrigin, FungibleAdapter as XcmCurrencyAdapter, FungiblesAdapter, HashedDescription,
45
	NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
46
	SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation,
47
	TakeWeightCredit, UsingComponents, WeightInfoBounds, WithComputedOrigin,
48
};
49

            
50
use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling};
51
use xcm::latest::prelude::{
52
	Asset, GlobalConsensus, InteriorLocation, Junction, Location, NetworkId, PalletInstance,
53
	Parachain,
54
};
55
use xcm_executor::traits::{CallDispatcher, ConvertLocation, JustTry};
56

            
57
use cumulus_primitives_core::{AggregateMessageOrigin, ParaId};
58
use orml_xcm_support::MultiNativeAsset;
59
use xcm_primitives::{
60
	AbsoluteAndRelativeReserve, AccountIdToCurrencyId, AccountIdToLocation, AsAssetType,
61
	FirstAssetTrader, SignedToAccountId20, UtilityAvailableCalls, UtilityEncodeCall, XcmTransact,
62
};
63

            
64
use parity_scale_codec::{Decode, Encode};
65
use scale_info::TypeInfo;
66

            
67
use sp_core::Get;
68
use sp_std::{
69
	convert::{From, Into, TryFrom},
70
	prelude::*,
71
};
72

            
73
use orml_traits::parameter_type_with_key;
74

            
75
use crate::governance::referenda::{FastGeneralAdminOrRoot, GeneralAdminOrRoot};
76

            
77
parameter_types! {
78
	// The network Id of the relay
79
	pub const RelayNetwork: NetworkId = NetworkId::Kusama;
80
	// The relay chain Origin type
81
	pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
82
	// The universal location within the global consensus system
83
	pub UniversalLocation: InteriorLocation =
84
		[GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into();
85

            
86
	// Self Reserve location, defines the multilocation identifying the self-reserve currency
87
	// This is used to match it also against our Balances pallet when we receive such
88
	// a Location: (Self Balances pallet index)
89
	// We use the RELATIVE multilocation
90
	pub SelfReserve: Location = Location {
91
		parents:0,
92
		interior: [
93
			PalletInstance(<Balances as PalletInfoAccess>::index() as u8)
94
		].into()
95
	};
96
}
97

            
98
/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used
99
/// when determining ownership of accounts for asset transacting and when attempting to use XCM
100
/// `Transact` in order to determine the dispatch Origin.
101
pub type LocationToAccountId = (
102
	// The parent (Relay-chain) origin converts to the default `AccountId`.
103
	ParentIsPreset<AccountId>,
104
	// Sibling parachain origins convert to AccountId via the `ParaId::into`.
105
	SiblingParachainConvertsVia<polkadot_parachain::primitives::Sibling, AccountId>,
106
	// If we receive a Location of type AccountKey20, just generate a native account
107
	AccountKey20Aliases<RelayNetwork, AccountId>,
108
	// Generate remote accounts according to polkadot standards
109
	HashedDescription<AccountId, DescribeFamily<DescribeAllTerminal>>,
110
);
111

            
112
/// Wrapper type around `LocationToAccountId` to convert an `AccountId` to type `H160`.
113
pub struct LocationToH160;
114
impl ConvertLocation<H160> for LocationToH160 {
115
	fn convert_location(location: &Location) -> Option<H160> {
116
		<LocationToAccountId as ConvertLocation<AccountId>>::convert_location(location)
117
			.map(Into::into)
118
	}
119
}
120

            
121
// The non-reserve fungible transactor type
122
// It will use pallet-assets, and the Id will be matched against AsAssetType
123
pub type ForeignFungiblesTransactor = FungiblesAdapter<
124
	// Use this fungibles implementation:
125
	super::Assets,
126
	// Use this currency when it is a fungible asset matching the given location or name:
127
	(
128
		ConvertedConcreteId<
129
			AssetId,
130
			Balance,
131
			AsAssetType<AssetId, AssetType, AssetManager>,
132
			JustTry,
133
		>,
134
	),
135
	// Do a simple punn to convert an AccountId20 Location into a native chain account ID:
136
	LocationToAccountId,
137
	// Our chain's account ID type (we can't get away without mentioning it explicitly):
138
	AccountId,
139
	// We dont allow teleports.
140
	NoChecking,
141
	// We dont track any teleports
142
	(),
143
>;
144

            
145
/// The transactor for our own chain currency.
146
pub type LocalAssetTransactor = XcmCurrencyAdapter<
147
	// Use this currency:
148
	Balances,
149
	// Use this currency when it is a fungible asset matching any of the locations in
150
	// SelfReserveRepresentations
151
	xcm_builder::IsConcrete<SelfReserve>,
152
	// We can convert the MultiLocations with our converter above:
153
	LocationToAccountId,
154
	// Our chain's account ID type (we can't get away without mentioning it explicitly):
155
	AccountId,
156
	// We dont allow teleport
157
	(),
158
>;
159

            
160
// We use all transactors
161
// These correspond to
162
// SelfReserve asset, both pre and post 0.9.16
163
// Foreign assets
164
// Local assets, both pre and post 0.9.16
165
// We can remove the Old reanchor once
166
// we import https://github.com/open-web3-stack/open-runtime-module-library/pull/708
167
pub type AssetTransactors = (
168
	LocalAssetTransactor,
169
	ForeignFungiblesTransactor,
170
	Erc20XcmBridge,
171
);
172

            
173
/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
174
/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
175
/// biases the kind of local `Origin` it will become.
176
pub type XcmOriginToTransactDispatchOrigin = (
177
	// Sovereign account converter; this attempts to derive an `AccountId` from the origin location
178
	// using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
179
	// foreign chains who want to have a local sovereign account on this chain which they control.
180
	SovereignSignedViaLocation<LocationToAccountId, RuntimeOrigin>,
181
	// Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when
182
	// recognised.
183
	RelayChainAsNative<RelayChainOrigin, RuntimeOrigin>,
184
	// Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
185
	// recognised.
186
	SiblingParachainAsNative<cumulus_pallet_xcm::Origin, RuntimeOrigin>,
187
	// Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
188
	pallet_xcm::XcmPassthrough<RuntimeOrigin>,
189
	// Xcm Origins defined by a Multilocation of type AccountKey20 can be converted to a 20 byte-
190
	// account local origin
191
	SignedAccountKey20AsNative<RelayNetwork, RuntimeOrigin>,
192
);
193

            
194
parameter_types! {
195
	/// The amount of weight an XCM operation takes. This is safe overestimate.
196
	pub UnitWeightCost: Weight = Weight::from_parts(200_000_000u64, 0);
197
	/// Maximum number of instructions in a single XCM fragment. A sanity check against
198
	/// weight caculations getting too crazy.
199
	pub MaxInstructions: u32 = 100;
200
}
201

            
202
/// Xcm Weigher shared between multiple Xcm-related configs.
203
pub type XcmWeigher = WeightInfoBounds<
204
	moonbeam_xcm_benchmarks::weights::XcmWeight<Runtime, RuntimeCall>,
205
	RuntimeCall,
206
	MaxInstructions,
207
>;
208

            
209
pub type XcmBarrier = (
210
	// Weight that is paid for may be consumed.
211
	TakeWeightCredit,
212
	// Expected responses are OK.
213
	AllowKnownQueryResponses<PolkadotXcm>,
214
	WithComputedOrigin<
215
		(
216
			// If the message is one that immediately attemps to pay for execution, then allow it.
217
			AllowTopLevelPaidExecutionFrom<Everything>,
218
			// Subscriptions for version tracking are OK.
219
			AllowSubscriptionsFrom<Everything>,
220
		),
221
		UniversalLocation,
222
		ConstU32<8>,
223
	>,
224
);
225

            
226
parameter_types! {
227
	/// Xcm fees will go to the treasury account
228
	pub XcmFeesAccount: AccountId = Treasury::account_id();
229
}
230

            
231
/// This is the struct that will handle the revenue from xcm fees
232
/// We do not burn anything because we want to mimic exactly what
233
/// the sovereign account has
234
pub type XcmFeesToAccount = xcm_primitives::XcmFeesToAccount<
235
	super::Assets,
236
	(
237
		ConvertedConcreteId<
238
			AssetId,
239
			Balance,
240
			AsAssetType<AssetId, AssetType, AssetManager>,
241
			JustTry,
242
		>,
243
	),
244
	AccountId,
245
	XcmFeesAccount,
246
>;
247

            
248
pub struct SafeCallFilter;
249
impl frame_support::traits::Contains<RuntimeCall> for SafeCallFilter {
250
	fn contains(_call: &RuntimeCall) -> bool {
251
		// TODO review
252
		// This needs to be addressed at EVM level
253
		true
254
	}
255
}
256

            
257
parameter_types! {
258
	pub const MaxAssetsIntoHolding: u32 = xcm_primitives::MAX_ASSETS;
259
}
260

            
261
// Our implementation of the Moonbeam Call
262
// Attachs the right origin in case the call is made to pallet-ethereum-xcm
263
#[cfg(not(feature = "evm-tracing"))]
264
moonbeam_runtime_common::impl_moonbeam_xcm_call!();
265
#[cfg(feature = "evm-tracing")]
266
moonbeam_runtime_common::impl_moonbeam_xcm_call_tracing!();
267

            
268
moonbeam_runtime_common::impl_evm_runner_precompile_or_eth_xcm!();
269

            
270
pub struct XcmExecutorConfig;
271
impl xcm_executor::Config for XcmExecutorConfig {
272
	type RuntimeCall = RuntimeCall;
273
	type XcmSender = XcmRouter;
274
	// How to withdraw and deposit an asset.
275
	type AssetTransactor = AssetTransactors;
276
	type OriginConverter = XcmOriginToTransactDispatchOrigin;
277
	// Filter to the reserve withdraw operations
278
	// Whenever the reserve matches the relative or absolute value
279
	// of our chain, we always return the relative reserve
280
	type IsReserve = MultiNativeAsset<AbsoluteAndRelativeReserve<SelfLocationAbsolute>>;
281
	type IsTeleporter = (); // No teleport
282
	type UniversalLocation = UniversalLocation;
283
	type Barrier = XcmBarrier;
284
	type Weigher = XcmWeigher;
285
	// We use two traders
286
	// When we receive the relative representation of the self-reserve asset,
287
	// we use UsingComponents and the local way of handling fees
288
	// When we receive a non-reserve asset, we use AssetManager to fetch how many
289
	// units per second we should charge
290
	type Trader = (
291
		UsingComponents<
292
			<Runtime as pallet_transaction_payment::Config>::WeightToFee,
293
			SelfReserve,
294
			AccountId,
295
			Balances,
296
			DealWithFees<Runtime>,
297
		>,
298
		FirstAssetTrader<AssetType, AssetManager, XcmFeesToAccount>,
299
	);
300
	type ResponseHandler = PolkadotXcm;
301
	type SubscriptionService = PolkadotXcm;
302
	type AssetTrap = pallet_erc20_xcm_bridge::AssetTrapWrapper<PolkadotXcm, Runtime>;
303
	type AssetClaims = PolkadotXcm;
304
	type CallDispatcher = MoonbeamCall;
305
	type PalletInstancesInfo = crate::AllPalletsWithSystem;
306
	type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
307
	type AssetLocker = ();
308
	type AssetExchanger = ();
309
	type FeeManager = ();
310
	type MessageExporter = ();
311
	type UniversalAliases = Nothing;
312
	type SafeCallFilter = SafeCallFilter;
313
	type Aliasers = Nothing;
314
	type TransactionalProcessor = xcm_builder::FrameTransactionalProcessor;
315
	type HrmpNewChannelOpenRequestHandler = ();
316
	type HrmpChannelAcceptedHandler = ();
317
	type HrmpChannelClosingHandler = ();
318
}
319

            
320
type XcmExecutor = pallet_erc20_xcm_bridge::XcmExecutorWrapper<
321
	XcmExecutorConfig,
322
	xcm_executor::XcmExecutor<XcmExecutorConfig>,
323
>;
324

            
325
// Converts a Signed Local Origin into a Location
326
pub type LocalOriginToLocation = SignedToAccountId20<RuntimeOrigin, AccountId, RelayNetwork>;
327

            
328
/// The means for routing XCM messages which are not for local execution into the right message
329
/// queues.
330
pub type XcmRouter = (
331
	// Two routers - use UMP to communicate with the relay chain:
332
	cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, ()>,
333
	// ..and XCMP to communicate with the sibling chains.
334
	XcmpQueue,
335
);
336

            
337
impl pallet_xcm::Config for Runtime {
338
	type RuntimeEvent = RuntimeEvent;
339
	type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
340
	type XcmRouter = XcmRouter;
341
	type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
342
	type XcmExecuteFilter = Nothing;
343
	type XcmExecutor = XcmExecutor;
344
	type XcmTeleportFilter = Nothing;
345
	type XcmReserveTransferFilter = Everything;
346
	type Weigher = XcmWeigher;
347
	type UniversalLocation = UniversalLocation;
348
	type RuntimeOrigin = RuntimeOrigin;
349
	type RuntimeCall = RuntimeCall;
350
	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
351
	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
352
	type Currency = Balances;
353
	type CurrencyMatcher = ();
354
	type TrustedLockers = ();
355
	type SovereignAccountOf = LocationToAccountId;
356
	type MaxLockers = ConstU32<8>;
357
	type MaxRemoteLockConsumers = ConstU32<0>;
358
	type RemoteLockConsumerIdentifier = ();
359
	// TODO pallet-xcm weights
360
	type WeightInfo = moonbeam_weights::pallet_xcm::WeightInfo<Runtime>;
361
	type AdminOrigin = EnsureRoot<AccountId>;
362
}
363

            
364
impl cumulus_pallet_xcm::Config for Runtime {
365
	type RuntimeEvent = RuntimeEvent;
366
	type XcmExecutor = XcmExecutor;
367
}
368

            
369
impl cumulus_pallet_xcmp_queue::Config for Runtime {
370
	type RuntimeEvent = RuntimeEvent;
371
	type ChannelInfo = ParachainSystem;
372
	type VersionWrapper = PolkadotXcm;
373
	type XcmpQueue = TransformOrigin<MessageQueue, AggregateMessageOrigin, ParaId, ParaIdToSibling>;
374
	type MaxInboundSuspended = sp_core::ConstU32<1_000>;
375
	type ControllerOrigin = EnsureRoot<AccountId>;
376
	type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
377
	type WeightInfo = moonbeam_weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>;
378
	type PriceForSiblingDelivery = polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery<
379
		cumulus_primitives_core::ParaId,
380
	>;
381
}
382

            
383
parameter_types! {
384
	pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent;
385
}
386

            
387
// TODO: This pallet can be removed after the lazy migration is done and
388
// event `Completed` is emitted.
389
// https://github.com/paritytech/polkadot-sdk/pull/1246
390
impl cumulus_pallet_dmp_queue::Config for Runtime {
391
	type RuntimeEvent = RuntimeEvent;
392
	type DmpSink = frame_support::traits::EnqueueWithOrigin<MessageQueue, RelayOrigin>;
393
	type WeightInfo = cumulus_pallet_dmp_queue::weights::SubstrateWeight<Runtime>;
394
}
395

            
396
parameter_types! {
397
	/// The amount of weight (if any) which should be provided to the message queue for
398
	/// servicing enqueued items.
399
	///
400
	/// This may be legitimately `None` in the case that you will call
401
	/// `ServiceQueues::service_queues` manually.
402
	pub MessageQueueServiceWeight: Weight =
403
		Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block;
404
	/// The maximum number of stale pages (i.e. of overweight messages) allowed before culling
405
	/// can happen. Once there are more stale pages than this, then historical pages may be
406
	/// dropped, even if they contain unprocessed overweight messages.
407
	pub const MessageQueueMaxStale: u32 = 8;
408
	/// The size of the page; this implies the maximum message size which can be sent.
409
	///
410
	/// A good value depends on the expected message sizes, their weights, the weight that is
411
	/// available for processing them and the maximal needed message size. The maximal message
412
	/// size is slightly lower than this as defined by [`MaxMessageLenOf`].
413
	pub const MessageQueueHeapSize: u32 = 128 * 1048;
414
}
415

            
416
impl pallet_message_queue::Config for Runtime {
417
	type RuntimeEvent = RuntimeEvent;
418
	#[cfg(feature = "runtime-benchmarks")]
419
	type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor<
420
		cumulus_primitives_core::AggregateMessageOrigin,
421
	>;
422
	#[cfg(not(feature = "runtime-benchmarks"))]
423
	type MessageProcessor =
424
		xcm_builder::ProcessXcmMessage<AggregateMessageOrigin, XcmExecutor, RuntimeCall>;
425
	type Size = u32;
426
	type HeapSize = MessageQueueHeapSize;
427
	type MaxStale = MessageQueueMaxStale;
428
	type ServiceWeight = MessageQueueServiceWeight;
429
	// The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin:
430
	type QueueChangeHandler = NarrowOriginToSibling<XcmpQueue>;
431
	// NarrowOriginToSibling calls XcmpQueue's is_paused if Origin is sibling. Allows all other origins
432
	type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling<XcmpQueue>);
433
	type WeightInfo = pallet_message_queue::weights::SubstrateWeight<Runtime>;
434
	type IdleMaxServiceWeight = MessageQueueServiceWeight;
435
}
436

            
437
// Our AssetType. For now we only handle Xcm Assets
438
8
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
439
pub enum AssetType {
440
74
	Xcm(xcm::v3::Location),
441
}
442
impl Default for AssetType {
443
	fn default() -> Self {
444
		Self::Xcm(xcm::v3::Location::here())
445
	}
446
}
447

            
448
impl From<xcm::v3::Location> for AssetType {
449
432
	fn from(location: xcm::v3::Location) -> Self {
450
432
		Self::Xcm(location)
451
432
	}
452
}
453

            
454
// This can be removed once we fully adopt xcm::v4 everywhere
455
impl TryFrom<Location> for AssetType {
456
	type Error = ();
457
232
	fn try_from(location: Location) -> Result<Self, Self::Error> {
458
232
		Ok(Self::Xcm(location.try_into()?))
459
232
	}
460
}
461

            
462
impl Into<Option<xcm::v3::Location>> for AssetType {
463
152
	fn into(self) -> Option<xcm::v3::Location> {
464
152
		match self {
465
152
			Self::Xcm(location) => Some(location),
466
152
		}
467
152
	}
468
}
469

            
470
impl Into<Option<Location>> for AssetType {
471
	fn into(self) -> Option<Location> {
472
		match self {
473
			Self::Xcm(location) => {
474
				xcm_builder::WithLatestLocationConverter::convert_back(&location)
475
			}
476
		}
477
	}
478
}
479

            
480
// Implementation on how to retrieve the AssetId from an AssetType
481
// We simply hash the AssetType and take the lowest 128 bits
482
impl From<AssetType> for AssetId {
483
616
	fn from(asset: AssetType) -> AssetId {
484
616
		match asset {
485
616
			AssetType::Xcm(id) => {
486
616
				let mut result: [u8; 16] = [0u8; 16];
487
616
				let hash: H256 = id.using_encoded(<Runtime as frame_system::Config>::Hashing::hash);
488
616
				result.copy_from_slice(&hash.as_fixed_bytes()[0..16]);
489
616
				u128::from_le_bytes(result)
490
616
			}
491
616
		}
492
616
	}
493
}
494

            
495
// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id.
496
24
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
497
pub enum CurrencyId {
498
	// Our native token
499
	SelfReserve,
500
	// Assets representing other chains native tokens
501
	ForeignAsset(AssetId),
502
	// Erc20 token
503
	Erc20 { contract_address: H160 },
504
}
505

            
506
impl AccountIdToCurrencyId<AccountId, CurrencyId> for Runtime {
507
8
	fn account_to_currency_id(account: AccountId) -> Option<CurrencyId> {
508
8
		Some(match account {
509
			// the self-reserve currency is identified by the pallet-balances address
510
8
			a if a == H160::from_low_u64_be(2050).into() => CurrencyId::SelfReserve,
511
			// the rest of the currencies, by their corresponding erc20 address
512
8
			_ => match Runtime::account_to_asset_id(account) {
513
				// A foreign asset
514
8
				Some((_prefix, asset_id)) => CurrencyId::ForeignAsset(asset_id),
515
				// If no known prefix is identified, we consider that it's a "real" erc20 token
516
				// (i.e. managed by a real smart contract)
517
				None => CurrencyId::Erc20 {
518
					contract_address: account.into(),
519
				},
520
			},
521
		})
522
8
	}
523
}
524

            
525
// How to convert from CurrencyId to Location
526
pub struct CurrencyIdToLocation<AssetXConverter>(sp_std::marker::PhantomData<AssetXConverter>);
527
impl<AssetXConverter> sp_runtime::traits::Convert<CurrencyId, Option<Location>>
528
	for CurrencyIdToLocation<AssetXConverter>
529
where
530
	AssetXConverter: MaybeEquivalence<Location, AssetId>,
531
{
532
20
	fn convert(currency: CurrencyId) -> Option<Location> {
533
20
		match currency {
534
			// For now and until Xtokens is adapted to handle 0.9.16 version we use
535
			// the old anchoring here
536
			// This is not a problem in either cases, since the view of the destination
537
			// chain does not change
538
			// TODO! change this to NewAnchoringSelfReserve once xtokens is adapted for it
539
			CurrencyId::SelfReserve => {
540
				let multi: Location = SelfReserve::get();
541
				Some(multi)
542
			}
543
20
			CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset),
544
			CurrencyId::Erc20 { contract_address } => {
545
				let mut location = Erc20XcmBridgePalletLocation::get();
546
				location
547
					.push_interior(Junction::AccountKey20 {
548
						key: contract_address.0,
549
						network: None,
550
					})
551
					.ok();
552
				Some(location)
553
			}
554
		}
555
20
	}
556
}
557

            
558
parameter_types! {
559
	pub const BaseXcmWeight: Weight = Weight::from_parts(200_000_000u64, 0);
560
	pub const MaxAssetsForTransfer: usize = 2;
561

            
562
	// This is how we are going to detect whether the asset is a Reserve asset
563
	// This however is the chain part only
564
	pub SelfLocation: Location = Location::here();
565
	// We need this to be able to catch when someone is trying to execute a non-
566
	// cross-chain transfer in xtokens through the absolute path way
567
	pub SelfLocationAbsolute: Location = Location {
568
		parents:1,
569
		interior: [
570
			Parachain(ParachainInfo::parachain_id().into())
571
		].into()
572
	};
573
}
574

            
575
parameter_type_with_key! {
576
	pub ParachainMinFee: |location: Location| -> Option<u128> {
577
		match (location.parents, location.first_interior()) {
578
			// Kusama AssetHub fee
579
			(1, Some(Parachain(1000u32))) => Some(50_000_000u128),
580
			_ => None,
581
		}
582
	};
583
}
584

            
585
impl orml_xtokens::Config for Runtime {
586
	type RuntimeEvent = RuntimeEvent;
587
	type Balance = Balance;
588
	type CurrencyId = CurrencyId;
589
	type AccountIdToLocation = AccountIdToLocation<AccountId>;
590
	type CurrencyIdConvert = CurrencyIdToLocation<AsAssetType<AssetId, AssetType, AssetManager>>;
591
	type XcmExecutor = XcmExecutor;
592
	type SelfLocation = SelfLocation;
593
	type Weigher = XcmWeigher;
594
	type BaseXcmWeight = BaseXcmWeight;
595
	type UniversalLocation = UniversalLocation;
596
	type MaxAssetsForTransfer = MaxAssetsForTransfer;
597
	type MinXcmFee = ParachainMinFee;
598
	type LocationsFilter = Everything;
599
	type ReserveProvider = AbsoluteAndRelativeReserve<SelfLocationAbsolute>;
600
	type RateLimiter = ();
601
	type RateLimiterId = ();
602
}
603

            
604
// 1 KSM should be enough
605
parameter_types! {
606
	pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into();
607
}
608

            
609
// For now we only allow to transact in the relay, although this might change in the future
610
// Transactors just defines the chains in which we allow transactions to be issued through
611
// xcm
612
8
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
613
pub enum Transactors {
614
	Relay,
615
}
616

            
617
// Default for benchmarking
618
#[cfg(feature = "runtime-benchmarks")]
619
impl Default for Transactors {
620
	fn default() -> Self {
621
		Transactors::Relay
622
	}
623
}
624

            
625
impl TryFrom<u8> for Transactors {
626
	type Error = ();
627
	fn try_from(value: u8) -> Result<Self, Self::Error> {
628
		match value {
629
			0u8 => Ok(Transactors::Relay),
630
			_ => Err(()),
631
		}
632
	}
633
}
634

            
635
impl UtilityEncodeCall for Transactors {
636
16
	fn encode_call(self, call: UtilityAvailableCalls) -> Vec<u8> {
637
16
		match self {
638
16
			Transactors::Relay => pallet_xcm_transactor::Pallet::<Runtime>::encode_call(
639
16
				pallet_xcm_transactor::Pallet(sp_std::marker::PhantomData::<Runtime>),
640
16
				call,
641
16
			),
642
16
		}
643
16
	}
644
}
645

            
646
impl XcmTransact for Transactors {
647
16
	fn destination(self) -> Location {
648
16
		match self {
649
16
			Transactors::Relay => Location::parent(),
650
16
		}
651
16
	}
652
}
653

            
654
pub type DerivativeAddressRegistrationOrigin =
655
	EitherOfDiverse<EnsureRoot<AccountId>, governance::custom_origins::GeneralAdmin>;
656

            
657
impl pallet_xcm_transactor::Config for Runtime {
658
	type RuntimeEvent = RuntimeEvent;
659
	type Balance = Balance;
660
	type Transactor = Transactors;
661
	type DerivativeAddressRegistrationOrigin = DerivativeAddressRegistrationOrigin;
662
	type SovereignAccountDispatcherOrigin = EnsureRoot<AccountId>;
663
	type CurrencyId = CurrencyId;
664
	type AccountIdToLocation = AccountIdToLocation<AccountId>;
665
	type CurrencyIdToLocation = CurrencyIdToLocation<AsAssetType<AssetId, AssetType, AssetManager>>;
666
	type XcmSender = XcmRouter;
667
	type SelfLocation = SelfLocation;
668
	type Weigher = XcmWeigher;
669
	type UniversalLocation = UniversalLocation;
670
	type BaseXcmWeight = BaseXcmWeight;
671
	type AssetTransactor = AssetTransactors;
672
	type ReserveProvider = AbsoluteAndRelativeReserve<SelfLocationAbsolute>;
673
	type WeightInfo = moonbeam_weights::pallet_xcm_transactor::WeightInfo<Runtime>;
674
	type HrmpManipulatorOrigin = GeneralAdminOrRoot;
675
	type HrmpOpenOrigin = FastGeneralAdminOrRoot;
676
	type MaxHrmpFee = xcm_builder::Case<MaxHrmpRelayFee>;
677
}
678

            
679
parameter_types! {
680
	// This is the relative view of erc20 assets.
681
	// Identified by this prefix + AccountKey20(contractAddress)
682
	// We use the RELATIVE multilocation
683
	pub Erc20XcmBridgePalletLocation: Location = Location {
684
		parents:0,
685
		interior: [
686
			PalletInstance(<Erc20XcmBridge as PalletInfoAccess>::index() as u8)
687
		].into()
688
	};
689

            
690
	// To be able to support almost all erc20 implementations,
691
	// we provide a sufficiently hight gas limit.
692
	pub Erc20XcmBridgeTransferGasLimit: u64 = 400_000;
693
}
694

            
695
impl pallet_erc20_xcm_bridge::Config for Runtime {
696
	type AccountIdConverter = LocationToH160;
697
	type Erc20MultilocationPrefix = Erc20XcmBridgePalletLocation;
698
	type Erc20TransferGasLimit = Erc20XcmBridgeTransferGasLimit;
699
	type EvmRunner = EvmRunnerPrecompileOrEthXcm<MoonbeamCall, Self>;
700
}
701

            
702
#[cfg(feature = "runtime-benchmarks")]
703
mod testing {
704
	use super::*;
705
	use xcm_builder::WithLatestLocationConverter;
706

            
707
	/// This From exists for benchmarking purposes. It has the potential side-effect of calling
708
	/// AssetManager::set_asset_type_asset_id() and should NOT be used in any production code.
709
	impl From<Location> for CurrencyId {
710
		fn from(location: Location) -> CurrencyId {
711
			use xcm_primitives::AssetTypeGetter;
712

            
713
			// If it does not exist, for benchmarking purposes, we create the association
714
			let asset_id = if let Some(asset_id) =
715
				AsAssetType::<AssetId, AssetType, AssetManager>::convert_location(&location)
716
			{
717
				asset_id
718
			} else {
719
				let asset_type = AssetType::Xcm(
720
					WithLatestLocationConverter::convert(&location).expect("convert to v3"),
721
				);
722
				let asset_id: AssetId = asset_type.clone().into();
723
				AssetManager::set_asset_type_asset_id(asset_type, asset_id);
724
				asset_id
725
			};
726

            
727
			CurrencyId::ForeignAsset(asset_id)
728
		}
729
	}
730
}