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, EmergencyParaXcm,
22
	Erc20XcmBridge, MaintenanceMode, MessageQueue, OpenTechCommitteeInstance, ParachainInfo,
23
	ParachainSystem, Perbill, PolkadotXcm, Runtime, RuntimeBlockWeights, RuntimeCall, RuntimeEvent,
24
	RuntimeOrigin, Treasury, XcmpQueue,
25
};
26

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

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

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

            
51
use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling};
52
use xcm::latest::prelude::{
53
	AllOf, Asset, AssetFilter, GlobalConsensus, InteriorLocation, Junction, Location, NetworkId,
54
	PalletInstance, Parachain, Wild, WildFungible,
55
};
56

            
57
use xcm_executor::traits::{CallDispatcher, ConvertLocation, JustTry};
58

            
59
use cumulus_primitives_core::{AggregateMessageOrigin, ParaId};
60
use xcm_primitives::{
61
	AbsoluteAndRelativeReserve, AccountIdToCurrencyId, AccountIdToLocation, AsAssetType,
62
	IsBridgedConcreteAssetFrom, MultiNativeAsset, SignedToAccountId20, UtilityAvailableCalls,
63
	UtilityEncodeCall, XcmTransact,
64
};
65

            
66
use parity_scale_codec::{Decode, Encode};
67
use scale_info::TypeInfo;
68

            
69
use sp_core::Get;
70
use sp_std::{
71
	convert::{From, Into, TryFrom},
72
	prelude::*,
73
};
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::Polkadot;
80
	// The relay chain Origin type
81
	pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
82
	pub UniversalLocation: InteriorLocation =
83
		[GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into();
84
	// Self Reserve location, defines the multilocation identifiying the self-reserve currency
85
	// This is used to match it also against our Balances pallet when we receive such
86
	// a Location: (Self Balances pallet index)
87
	// We use the RELATIVE multilocation
88
	pub SelfReserve: Location = Location {
89
		parents:0,
90
		interior: [
91
			PalletInstance(<Balances as PalletInfoAccess>::index() as u8)
92
		].into()
93
	};
94
}
95

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

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

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

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

            
158
// We use all transactors
159
pub type AssetTransactors = (
160
	LocalAssetTransactor,
161
	ForeignFungiblesTransactor,
162
	Erc20XcmBridge,
163
);
164

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

            
186
parameter_types! {
187
	/// Maximum number of instructions in a single XCM fragment. A sanity check against
188
	/// weight caculations getting too crazy.
189
	pub MaxInstructions: u32 = 100;
190
}
191

            
192
/// Xcm Weigher shared between multiple Xcm-related configs.
193
pub type XcmWeigher = WeightInfoBounds<
194
	moonbeam_xcm_benchmarks::weights::XcmWeight<Runtime, RuntimeCall>,
195
	RuntimeCall,
196
	MaxInstructions,
197
>;
198

            
199
pub type XcmBarrier = (
200
	// Weight that is paid for may be consumed.
201
	TakeWeightCredit,
202
	// Expected responses are OK.
203
	AllowKnownQueryResponses<PolkadotXcm>,
204
	WithComputedOrigin<
205
		(
206
			// If the message is one that immediately attemps to pay for execution, then allow it.
207
			AllowTopLevelPaidExecutionFrom<Everything>,
208
			// Subscriptions for version tracking are OK.
209
			AllowSubscriptionsFrom<Everything>,
210
		),
211
		UniversalLocation,
212
		ConstU32<8>,
213
	>,
214
);
215

            
216
parameter_types! {
217
	/// Xcm fees will go to the treasury account
218
	pub XcmFeesAccount: AccountId = Treasury::account_id();
219
}
220

            
221
pub struct SafeCallFilter;
222
impl frame_support::traits::Contains<RuntimeCall> for SafeCallFilter {
223
	fn contains(_call: &RuntimeCall) -> bool {
224
		// TODO review
225
		// This needs to be addressed at EVM level
226
		true
227
	}
228
}
229

            
230
parameter_types! {
231
	 /// Location of Asset Hub
232
	pub AssetHubLocation: Location = Location::new(1, [Parachain(1000)]);
233
	pub const RelayLocation: Location = Location::parent();
234
	pub RelayLocationFilter: AssetFilter = Wild(AllOf {
235
		fun: WildFungible,
236
		id: xcm::prelude::AssetId(RelayLocation::get()),
237
	});
238
	pub RelayChainNativeAssetFromAssetHub: (AssetFilter, Location) = (
239
		RelayLocationFilter::get(),
240
		AssetHubLocation::get()
241
	);
242
	pub const MaxAssetsIntoHolding: u32 = xcm_primitives::MAX_ASSETS;
243
}
244

            
245
type Reserves = (
246
	// Assets bridged from different consensus systems held in reserve on Asset Hub.
247
	IsBridgedConcreteAssetFrom<AssetHubLocation>,
248
	// Relaychain (DOT) from Asset Hub
249
	Case<RelayChainNativeAssetFromAssetHub>,
250
	// Assets which the reserve is the same as the origin.
251
	MultiNativeAsset<AbsoluteAndRelativeReserve<SelfLocationAbsolute>>,
252
);
253

            
254
// Our implementation of the Moonbeam Call
255
// Attachs the right origin in case the call is made to pallet-ethereum-xcm
256
#[cfg(not(feature = "evm-tracing"))]
257
moonbeam_runtime_common::impl_moonbeam_xcm_call!();
258
#[cfg(feature = "evm-tracing")]
259
moonbeam_runtime_common::impl_moonbeam_xcm_call_tracing!();
260

            
261
moonbeam_runtime_common::impl_evm_runner_precompile_or_eth_xcm!();
262

            
263
pub struct XcmExecutorConfig;
264
impl xcm_executor::Config for XcmExecutorConfig {
265
	type RuntimeCall = RuntimeCall;
266
	type XcmSender = XcmRouter;
267
	// How to withdraw and deposit an asset.
268
	type AssetTransactor = AssetTransactors;
269
	type OriginConverter = XcmOriginToTransactDispatchOrigin;
270
	// Filter to the reserve withdraw operations
271
	// Whenever the reserve matches the relative or absolute value
272
	// of our chain, we always return the relative reserve
273
	type IsReserve = Reserves;
274
	type IsTeleporter = (); // No teleport
275
	type UniversalLocation = UniversalLocation;
276
	type Barrier = XcmBarrier;
277
	type Weigher = XcmWeigher;
278
	// We use two traders
279
	// When we receive the relative representation of the self-reserve asset,
280
	// we use UsingComponents and the local way of handling fees
281
	// When we receive a non-reserve asset, we use AssetManager to fetch how many
282
	// units per second we should charge
283
	type Trader = pallet_xcm_weight_trader::Trader<Runtime>;
284
	type ResponseHandler = PolkadotXcm;
285
	type SubscriptionService = PolkadotXcm;
286
	type AssetTrap = pallet_erc20_xcm_bridge::AssetTrapWrapper<PolkadotXcm, Runtime>;
287
	type AssetClaims = PolkadotXcm;
288
	type CallDispatcher = MoonbeamCall;
289
	type PalletInstancesInfo = crate::AllPalletsWithSystem;
290
	type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
291
	type AssetLocker = ();
292
	type AssetExchanger = ();
293
	type FeeManager = ();
294
	type MessageExporter = ();
295
	type UniversalAliases = Nothing;
296
	type SafeCallFilter = SafeCallFilter;
297
	type Aliasers = Nothing;
298
	type TransactionalProcessor = xcm_builder::FrameTransactionalProcessor;
299
	type HrmpNewChannelOpenRequestHandler = ();
300
	type HrmpChannelAcceptedHandler = ();
301
	type HrmpChannelClosingHandler = ();
302
	type XcmRecorder = PolkadotXcm;
303
}
304

            
305
type XcmExecutor = pallet_erc20_xcm_bridge::XcmExecutorWrapper<
306
	XcmExecutorConfig,
307
	xcm_executor::XcmExecutor<XcmExecutorConfig>,
308
>;
309

            
310
// Converts a Signed Local Origin into a Location
311
pub type LocalOriginToLocation = SignedToAccountId20<RuntimeOrigin, AccountId, RelayNetwork>;
312

            
313
/// The means for routing XCM messages which are not for local execution into the right message
314
/// queues.
315
pub type XcmRouter = (
316
	// Two routers - use UMP to communicate with the relay chain:
317
	cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, ()>,
318
	// ..and XCMP to communicate with the sibling chains.
319
	XcmpQueue,
320
);
321

            
322
impl pallet_xcm::Config for Runtime {
323
	type RuntimeEvent = RuntimeEvent;
324
	type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
325
	type XcmRouter = XcmRouter;
326
	type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
327
	type XcmExecuteFilter = Nothing;
328
	type XcmExecutor = XcmExecutor;
329
	type XcmTeleportFilter = Nothing;
330
	type XcmReserveTransferFilter = Everything;
331
	type Weigher = XcmWeigher;
332
	type UniversalLocation = UniversalLocation;
333
	type RuntimeOrigin = RuntimeOrigin;
334
	type RuntimeCall = RuntimeCall;
335
	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
336
	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
337
	type Currency = Balances;
338
	type CurrencyMatcher = ();
339
	type TrustedLockers = ();
340
	type SovereignAccountOf = LocationToAccountId;
341
	type MaxLockers = ConstU32<8>;
342
	type MaxRemoteLockConsumers = ConstU32<0>;
343
	type RemoteLockConsumerIdentifier = ();
344
	type WeightInfo = moonbeam_weights::pallet_xcm::WeightInfo<Runtime>;
345
	type AdminOrigin = EnsureRoot<AccountId>;
346
}
347

            
348
impl cumulus_pallet_xcm::Config for Runtime {
349
	type RuntimeEvent = RuntimeEvent;
350
	type XcmExecutor = XcmExecutor;
351
}
352

            
353
impl cumulus_pallet_xcmp_queue::Config for Runtime {
354
	type RuntimeEvent = RuntimeEvent;
355
	type ChannelInfo = ParachainSystem;
356
	type VersionWrapper = PolkadotXcm;
357
	type XcmpQueue = TransformOrigin<MessageQueue, AggregateMessageOrigin, ParaId, ParaIdToSibling>;
358
	type MaxInboundSuspended = sp_core::ConstU32<1_000>;
359
	type ControllerOrigin = EnsureRoot<AccountId>;
360
	type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
361
	type WeightInfo = moonbeam_weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>;
362
	type PriceForSiblingDelivery = polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery<
363
		cumulus_primitives_core::ParaId,
364
	>;
365
	type MaxActiveOutboundChannels = ConstU32<128>;
366
	// Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we
367
	// need to set the page size larger than that until we reduce the channel size on-chain.
368
	type MaxPageSize = MessageQueueHeapSize;
369
}
370

            
371
parameter_types! {
372
	pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent;
373
}
374

            
375
parameter_types! {
376
	/// The amount of weight (if any) which should be provided to the message queue for
377
	/// servicing enqueued items.
378
	///
379
	/// This may be legitimately `None` in the case that you will call
380
	/// `ServiceQueues::service_queues` manually.
381
	pub MessageQueueServiceWeight: Weight =
382
		Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block;
383
	/// The maximum number of stale pages (i.e. of overweight messages) allowed before culling
384
	/// can happen. Once there are more stale pages than this, then historical pages may be
385
	/// dropped, even if they contain unprocessed overweight messages.
386
	pub const MessageQueueMaxStale: u32 = 8;
387
	/// The size of the page; this implies the maximum message size which can be sent.
388
	///
389
	/// A good value depends on the expected message sizes, their weights, the weight that is
390
	/// available for processing them and the maximal needed message size. The maximal message
391
	/// size is slightly lower than this as defined by [`MaxMessageLenOf`].
392
	pub const MessageQueueHeapSize: u32 = 103 * 1024;
393
}
394

            
395
impl pallet_message_queue::Config for Runtime {
396
	type RuntimeEvent = RuntimeEvent;
397
	#[cfg(feature = "runtime-benchmarks")]
398
	type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor<
399
		cumulus_primitives_core::AggregateMessageOrigin,
400
	>;
401
	#[cfg(not(feature = "runtime-benchmarks"))]
402
	type MessageProcessor = pallet_ethereum_xcm::MessageProcessorWrapper<
403
		xcm_builder::ProcessXcmMessage<AggregateMessageOrigin, XcmExecutor, RuntimeCall>,
404
	>;
405
	type Size = u32;
406
	type HeapSize = MessageQueueHeapSize;
407
	type MaxStale = MessageQueueMaxStale;
408
	type ServiceWeight = MessageQueueServiceWeight;
409
	// The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin:
410
	type QueueChangeHandler = NarrowOriginToSibling<XcmpQueue>;
411
	// NarrowOriginToSibling calls XcmpQueue's is_paused if Origin is sibling. Allows all other origins
412
	type QueuePausedQuery = EmergencyParaXcm;
413
	type WeightInfo = moonbeam_weights::pallet_message_queue::WeightInfo<Runtime>;
414
	type IdleMaxServiceWeight = MessageQueueServiceWeight;
415
}
416

            
417
pub type FastAuthorizeUpgradeOrigin = EitherOfDiverse<
418
	EnsureRoot<AccountId>,
419
	pallet_collective::EnsureProportionAtLeast<AccountId, OpenTechCommitteeInstance, 5, 9>,
420
>;
421

            
422
pub type ResumeXcmOrigin = EitherOfDiverse<
423
	EnsureRoot<AccountId>,
424
	pallet_collective::EnsureProportionAtLeast<AccountId, OpenTechCommitteeInstance, 5, 9>,
425
>;
426

            
427
impl pallet_emergency_para_xcm::Config for Runtime {
428
	type RuntimeEvent = RuntimeEvent;
429
	type CheckAssociatedRelayNumber =
430
		cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases;
431
	type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling<XcmpQueue>);
432
	type PausedThreshold = ConstU32<300>;
433
	type FastAuthorizeUpgradeOrigin = FastAuthorizeUpgradeOrigin;
434
	type PausedToNormalOrigin = ResumeXcmOrigin;
435
}
436

            
437
// Our AssetType. For now we only handle Xcm Assets
438
6
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
439
pub enum AssetType {
440
26
	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
420
	fn from(location: xcm::v3::Location) -> Self {
450
420
		Self::Xcm(location)
451
420
	}
452
}
453

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

            
462
impl Into<Option<xcm::v3::Location>> for AssetType {
463
132
	fn into(self) -> Option<xcm::v3::Location> {
464
132
		match self {
465
132
			Self::Xcm(location) => Some(location),
466
132
		}
467
132
	}
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
522
	fn from(asset: AssetType) -> AssetId {
484
522
		match asset {
485
522
			AssetType::Xcm(id) => {
486
522
				let mut result: [u8; 16] = [0u8; 16];
487
522
				let hash: H256 = id.using_encoded(<Runtime as frame_system::Config>::Hashing::hash);
488
522
				result.copy_from_slice(&hash.as_fixed_bytes()[0..16]);
489
522
				u128::from_le_bytes(result)
490
522
			}
491
522
		}
492
522
	}
493
}
494

            
495
// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id.
496
18
#[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
6
	fn account_to_currency_id(account: AccountId) -> Option<CurrencyId> {
508
6
		Some(match account {
509
			// the self-reserve currency is identified by the pallet-balances address
510
6
			a if a == H160::from_low_u64_be(2050).into() => CurrencyId::SelfReserve,
511
			// the rest of the currencies, by their corresponding erc20 address
512
6
			_ => match Runtime::account_to_asset_id(account) {
513
				// We distinguish by prefix, and depending on it we create either
514
				// Foreign or Local
515
6
				Some((_prefix, asset_id)) => CurrencyId::ForeignAsset(asset_id),
516
				// If no known prefix is identified, we consider that it's a "real" erc20 token
517
				// (i.e. managed by a real smart contract)
518
				None => CurrencyId::Erc20 {
519
					contract_address: account.into(),
520
				},
521
			},
522
		})
523
6
	}
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: sp_runtime::traits::MaybeEquivalence<Location, AssetId>,
531
{
532
5
	fn convert(currency: CurrencyId) -> Option<Location> {
533
5
		match currency {
534
			CurrencyId::SelfReserve => {
535
				let multi: Location = SelfReserve::get();
536
				Some(multi)
537
			}
538
5
			CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset),
539
			CurrencyId::Erc20 { contract_address } => {
540
				let mut location = Erc20XcmBridgePalletLocation::get();
541
				location
542
					.push_interior(Junction::AccountKey20 {
543
						key: contract_address.0,
544
						network: None,
545
					})
546
					.ok();
547
				Some(location)
548
			}
549
		}
550
5
	}
551
}
552

            
553
parameter_types! {
554
	pub const BaseXcmWeight: Weight = Weight::from_parts(200_000_000u64, 0);
555
	pub const MaxAssetsForTransfer: usize = 2;
556

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

            
570
// 1 DOT should be enough
571
parameter_types! {
572
	pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into();
573
}
574

            
575
// For now we only allow to transact in the relay, although this might change in the future
576
// Transactors just defines the chains in which we allow transactions to be issued through
577
// xcm
578
6
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
579
pub enum Transactors {
580
	Relay,
581
}
582

            
583
// Default for benchmarking
584
#[cfg(feature = "runtime-benchmarks")]
585
impl Default for Transactors {
586
	fn default() -> Self {
587
		Transactors::Relay
588
	}
589
}
590

            
591
impl TryFrom<u8> for Transactors {
592
	type Error = ();
593
	fn try_from(value: u8) -> Result<Self, Self::Error> {
594
		match value {
595
			0u8 => Ok(Transactors::Relay),
596
			_ => Err(()),
597
		}
598
	}
599
}
600

            
601
impl UtilityEncodeCall for Transactors {
602
12
	fn encode_call(self, call: UtilityAvailableCalls) -> Vec<u8> {
603
12
		match self {
604
12
			Transactors::Relay => pallet_xcm_transactor::Pallet::<Runtime>::encode_call(
605
12
				pallet_xcm_transactor::Pallet(sp_std::marker::PhantomData::<Runtime>),
606
12
				call,
607
12
			),
608
12
		}
609
12
	}
610
}
611

            
612
impl XcmTransact for Transactors {
613
12
	fn destination(self) -> Location {
614
12
		match self {
615
12
			Transactors::Relay => Location::parent(),
616
12
		}
617
12
	}
618
}
619

            
620
pub type DerivativeAddressRegistrationOrigin =
621
	EitherOfDiverse<EnsureRoot<AccountId>, governance::custom_origins::GeneralAdmin>;
622

            
623
impl pallet_xcm_transactor::Config for Runtime {
624
	type RuntimeEvent = RuntimeEvent;
625
	type Balance = Balance;
626
	type Transactor = Transactors;
627
	type DerivativeAddressRegistrationOrigin = DerivativeAddressRegistrationOrigin;
628
	type SovereignAccountDispatcherOrigin = EnsureRoot<AccountId>;
629
	type CurrencyId = CurrencyId;
630
	type AccountIdToLocation = AccountIdToLocation<AccountId>;
631
	type CurrencyIdToLocation = CurrencyIdToLocation<AsAssetType<AssetId, AssetType, AssetManager>>;
632
	type XcmSender = XcmRouter;
633
	type SelfLocation = SelfLocation;
634
	type Weigher = XcmWeigher;
635
	type UniversalLocation = UniversalLocation;
636
	type BaseXcmWeight = BaseXcmWeight;
637
	type AssetTransactor = AssetTransactors;
638
	type ReserveProvider = AbsoluteAndRelativeReserve<SelfLocationAbsolute>;
639
	type WeightInfo = moonbeam_weights::pallet_xcm_transactor::WeightInfo<Runtime>;
640
	type HrmpManipulatorOrigin = GeneralAdminOrRoot;
641
	type HrmpOpenOrigin = FastGeneralAdminOrRoot;
642
	type MaxHrmpFee = xcm_builder::Case<MaxHrmpRelayFee>;
643
}
644

            
645
parameter_types! {
646
	// This is the relative view of erc20 assets.
647
	// Identified by this prefix + AccountKey20(contractAddress)
648
	// We use the RELATIVE multilocation
649
	pub Erc20XcmBridgePalletLocation: Location = Location {
650
		parents:0,
651
		interior: [
652
			PalletInstance(<Erc20XcmBridge as PalletInfoAccess>::index() as u8)
653
		].into()
654
	};
655

            
656
	// To be able to support almost all erc20 implementations,
657
	// we provide a sufficiently hight gas limit.
658
	pub Erc20XcmBridgeTransferGasLimit: u64 = 800_000;
659
}
660

            
661
impl pallet_erc20_xcm_bridge::Config for Runtime {
662
	type AccountIdConverter = LocationToH160;
663
	type Erc20MultilocationPrefix = Erc20XcmBridgePalletLocation;
664
	type Erc20TransferGasLimit = Erc20XcmBridgeTransferGasLimit;
665
	type EvmRunner = EvmRunnerPrecompileOrEthXcm<MoonbeamCall, Self>;
666
}
667

            
668
pub struct AccountIdToH160;
669
impl sp_runtime::traits::Convert<AccountId, H160> for AccountIdToH160 {
670
	fn convert(account_id: AccountId) -> H160 {
671
		account_id.into()
672
	}
673
}
674

            
675
impl pallet_moonbeam_foreign_assets::Config for Runtime {
676
	type AccountIdToH160 = AccountIdToH160;
677
	type AssetIdFilter = Nothing;
678
	type EvmRunner = EvmRunnerPrecompileOrEthXcm<MoonbeamCall, Self>;
679
	type ForeignAssetCreatorOrigin = frame_system::EnsureNever<AccountId>;
680
	type ForeignAssetFreezerOrigin = frame_system::EnsureNever<AccountId>;
681
	type ForeignAssetModifierOrigin = frame_system::EnsureNever<AccountId>;
682
	type ForeignAssetUnfreezerOrigin = frame_system::EnsureNever<AccountId>;
683
	type OnForeignAssetCreated = ();
684
	type MaxForeignAssets = ConstU32<256>;
685
	type RuntimeEvent = RuntimeEvent;
686
	type WeightInfo = moonbeam_weights::pallet_moonbeam_foreign_assets::WeightInfo<Runtime>;
687
	type XcmLocationToH160 = LocationToH160;
688
}
689

            
690
pub struct AssetFeesFilter;
691
impl frame_support::traits::Contains<Location> for AssetFeesFilter {
692
	fn contains(location: &Location) -> bool {
693
		location.parent_count() > 0
694
			&& location.first_interior() != Erc20XcmBridgePalletLocation::get().first_interior()
695
	}
696
}
697

            
698
pub type AddSupportedAssetOrigin = EitherOfDiverse<
699
	EnsureRoot<AccountId>,
700
	EitherOfDiverse<
701
		pallet_collective::EnsureProportionMoreThan<AccountId, OpenTechCommitteeInstance, 5, 9>,
702
		governance::custom_origins::GeneralAdmin,
703
	>,
704
>;
705

            
706
pub type EditSupportedAssetOrigin = EitherOfDiverse<
707
	EnsureRoot<AccountId>,
708
	EitherOfDiverse<
709
		pallet_collective::EnsureProportionMoreThan<AccountId, OpenTechCommitteeInstance, 5, 9>,
710
		governance::custom_origins::FastGeneralAdmin,
711
	>,
712
>;
713

            
714
pub type RemoveSupportedAssetOrigin = EitherOfDiverse<
715
	EnsureRoot<AccountId>,
716
	pallet_collective::EnsureProportionMoreThan<AccountId, OpenTechCommitteeInstance, 5, 9>,
717
>;
718

            
719
impl pallet_xcm_weight_trader::Config for Runtime {
720
	type AccountIdToLocation = AccountIdToLocation<AccountId>;
721
	type AddSupportedAssetOrigin = AddSupportedAssetOrigin;
722
	type AssetLocationFilter = AssetFeesFilter;
723
	type AssetTransactor = AssetTransactors;
724
	type Balance = Balance;
725
	type EditSupportedAssetOrigin = EditSupportedAssetOrigin;
726
	type NativeLocation = SelfReserve;
727
	type PauseSupportedAssetOrigin = EditSupportedAssetOrigin;
728
	type RemoveSupportedAssetOrigin = RemoveSupportedAssetOrigin;
729
	type RuntimeEvent = RuntimeEvent;
730
	type ResumeSupportedAssetOrigin = RemoveSupportedAssetOrigin;
731
	type WeightInfo = moonbeam_weights::pallet_xcm_weight_trader::WeightInfo<Runtime>;
732
	type WeightToFee = <Runtime as pallet_transaction_payment::Config>::WeightToFee;
733
	type XcmFeesAccount = XcmFeesAccount;
734
	#[cfg(feature = "runtime-benchmarks")]
735
	type NotFilteredLocation = RelayLocation;
736
}
737

            
738
#[cfg(feature = "runtime-benchmarks")]
739
mod testing {
740
	use super::*;
741
	use xcm_builder::WithLatestLocationConverter;
742

            
743
	/// This From exists for benchmarking purposes. It has the potential side-effect of calling
744
	/// AssetManager::set_asset_type_asset_id() and should NOT be used in any production code.
745
	impl From<Location> for CurrencyId {
746
		fn from(location: Location) -> CurrencyId {
747
			use xcm_primitives::AssetTypeGetter;
748

            
749
			// If it does not exist, for benchmarking purposes, we create the association
750
			let asset_id = if let Some(asset_id) =
751
				AsAssetType::<AssetId, AssetType, AssetManager>::convert_location(&location)
752
			{
753
				asset_id
754
			} else {
755
				let asset_type = AssetType::Xcm(
756
					WithLatestLocationConverter::convert(&location).expect("convert to v3"),
757
				);
758
				let asset_id: AssetId = asset_type.clone().into();
759
				AssetManager::set_asset_type_asset_id(asset_type, asset_id);
760
				asset_id
761
			};
762

            
763
			CurrencyId::ForeignAsset(asset_id)
764
		}
765
	}
766
}