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::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
	/// The amount of weight an XCM operation takes. This is safe overestimate.
188
	pub UnitWeightCost: Weight = Weight::from_parts(200_000_000u64, 0);
189
	/// Maximum number of instructions in a single XCM fragment. A sanity check against
190
	/// weight caculations getting too crazy.
191
	pub MaxInstructions: u32 = 100;
192
}
193

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

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

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

            
223
/// This is the struct that will handle the revenue from xcm fees
224
/// We do not burn anything because we want to mimic exactly what
225
/// the sovereign account has
226
pub type XcmFeesToAccount = xcm_primitives::XcmFeesToAccount<
227
	super::Assets,
228
	(
229
		ConvertedConcreteId<
230
			AssetId,
231
			Balance,
232
			AsAssetType<AssetId, AssetType, AssetManager>,
233
			JustTry,
234
		>,
235
	),
236
	AccountId,
237
	XcmFeesAccount,
238
>;
239

            
240
pub struct SafeCallFilter;
241
impl frame_support::traits::Contains<RuntimeCall> for SafeCallFilter {
242
	fn contains(_call: &RuntimeCall) -> bool {
243
		// TODO review
244
		// This needs to be addressed at EVM level
245
		true
246
	}
247
}
248

            
249
parameter_types! {
250
	pub const MaxAssetsIntoHolding: u32 = xcm_primitives::MAX_ASSETS;
251
}
252

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

            
260
moonbeam_runtime_common::impl_evm_runner_precompile_or_eth_xcm!();
261

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

            
312
type XcmExecutor = pallet_erc20_xcm_bridge::XcmExecutorWrapper<
313
	XcmExecutorConfig,
314
	xcm_executor::XcmExecutor<XcmExecutorConfig>,
315
>;
316

            
317
// Converts a Signed Local Origin into a Location
318
pub type LocalOriginToLocation = SignedToAccountId20<RuntimeOrigin, AccountId, RelayNetwork>;
319

            
320
/// The means for routing XCM messages which are not for local execution into the right message
321
/// queues.
322
pub type XcmRouter = (
323
	// Two routers - use UMP to communicate with the relay chain:
324
	cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, ()>,
325
	// ..and XCMP to communicate with the sibling chains.
326
	XcmpQueue,
327
);
328

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

            
356
impl cumulus_pallet_xcm::Config for Runtime {
357
	type RuntimeEvent = RuntimeEvent;
358
	type XcmExecutor = XcmExecutor;
359
}
360

            
361
impl cumulus_pallet_xcmp_queue::Config for Runtime {
362
	type RuntimeEvent = RuntimeEvent;
363
	type ChannelInfo = ParachainSystem;
364
	type VersionWrapper = PolkadotXcm;
365
	type XcmpQueue = TransformOrigin<MessageQueue, AggregateMessageOrigin, ParaId, ParaIdToSibling>;
366
	type MaxInboundSuspended = sp_core::ConstU32<1_000>;
367
	type ControllerOrigin = EnsureRoot<AccountId>;
368
	type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
369
	type WeightInfo = moonbeam_weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>;
370
	type PriceForSiblingDelivery = polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery<
371
		cumulus_primitives_core::ParaId,
372
	>;
373
}
374

            
375
parameter_types! {
376
	pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent;
377
}
378

            
379
// TODO: This pallet can be removed after the lazy migration is done and
380
// event `Completed` is emitted.
381
// https://github.com/paritytech/polkadot-sdk/pull/1246
382
impl cumulus_pallet_dmp_queue::Config for Runtime {
383
	type RuntimeEvent = RuntimeEvent;
384
	type DmpSink = frame_support::traits::EnqueueWithOrigin<MessageQueue, RelayOrigin>;
385
	type WeightInfo = cumulus_pallet_dmp_queue::weights::SubstrateWeight<Runtime>;
386
}
387

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

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

            
429
// Our AssetType. For now we only handle Xcm Assets
430
6
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
431
pub enum AssetType {
432
66
	Xcm(xcm::v3::Location),
433
}
434
impl Default for AssetType {
435
	fn default() -> Self {
436
		Self::Xcm(xcm::v3::Location::here())
437
	}
438
}
439

            
440
impl From<xcm::v3::Location> for AssetType {
441
312
	fn from(location: xcm::v3::Location) -> Self {
442
312
		Self::Xcm(location)
443
312
	}
444
}
445

            
446
// This can be removed once we fully adopt xcm::v4 everywhere
447
impl TryFrom<Location> for AssetType {
448
	type Error = ();
449
162
	fn try_from(location: Location) -> Result<Self, Self::Error> {
450
162
		Ok(Self::Xcm(location.try_into()?))
451
162
	}
452
}
453

            
454
impl Into<Option<xcm::v3::Location>> for AssetType {
455
114
	fn into(self) -> Option<xcm::v3::Location> {
456
114
		match self {
457
114
			Self::Xcm(location) => Some(location),
458
114
		}
459
114
	}
460
}
461

            
462
impl Into<Option<Location>> for AssetType {
463
	fn into(self) -> Option<Location> {
464
		match self {
465
			Self::Xcm(location) => {
466
				xcm_builder::WithLatestLocationConverter::convert_back(&location)
467
			}
468
		}
469
	}
470
}
471

            
472
// Implementation on how to retrieve the AssetId from an AssetType
473
// We simply hash the AssetType and take the lowest 128 bits
474
impl From<AssetType> for AssetId {
475
438
	fn from(asset: AssetType) -> AssetId {
476
438
		match asset {
477
438
			AssetType::Xcm(id) => {
478
438
				let mut result: [u8; 16] = [0u8; 16];
479
438
				let hash: H256 = id.using_encoded(<Runtime as frame_system::Config>::Hashing::hash);
480
438
				result.copy_from_slice(&hash.as_fixed_bytes()[0..16]);
481
438
				u128::from_le_bytes(result)
482
438
			}
483
438
		}
484
438
	}
485
}
486

            
487
// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id.
488
18
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
489
pub enum CurrencyId {
490
	// Our native token
491
	SelfReserve,
492
	// Assets representing other chains native tokens
493
	ForeignAsset(AssetId),
494
	// Erc20 token
495
	Erc20 { contract_address: H160 },
496
}
497

            
498
impl AccountIdToCurrencyId<AccountId, CurrencyId> for Runtime {
499
6
	fn account_to_currency_id(account: AccountId) -> Option<CurrencyId> {
500
6
		Some(match account {
501
			// the self-reserve currency is identified by the pallet-balances address
502
6
			a if a == H160::from_low_u64_be(2050).into() => CurrencyId::SelfReserve,
503
			// the rest of the currencies, by their corresponding erc20 address
504
6
			_ => match Runtime::account_to_asset_id(account) {
505
				// We distinguish by prefix, and depending on it we create either
506
				// Foreign or Local
507
6
				Some((_prefix, asset_id)) => CurrencyId::ForeignAsset(asset_id),
508
				// If no known prefix is identified, we consider that it's a "real" erc20 token
509
				// (i.e. managed by a real smart contract)
510
				None => CurrencyId::Erc20 {
511
					contract_address: account.into(),
512
				},
513
			},
514
		})
515
6
	}
516
}
517
// How to convert from CurrencyId to Location
518
pub struct CurrencyIdToLocation<AssetXConverter>(sp_std::marker::PhantomData<AssetXConverter>);
519
impl<AssetXConverter> sp_runtime::traits::Convert<CurrencyId, Option<Location>>
520
	for CurrencyIdToLocation<AssetXConverter>
521
where
522
	AssetXConverter: sp_runtime::traits::MaybeEquivalence<Location, AssetId>,
523
{
524
17
	fn convert(currency: CurrencyId) -> Option<Location> {
525
17
		match currency {
526
			CurrencyId::SelfReserve => {
527
1
				let multi: Location = SelfReserve::get();
528
1
				Some(multi)
529
			}
530
16
			CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset),
531
			CurrencyId::Erc20 { contract_address } => {
532
				let mut location = Erc20XcmBridgePalletLocation::get();
533
				location
534
					.push_interior(Junction::AccountKey20 {
535
						key: contract_address.0,
536
						network: None,
537
					})
538
					.ok();
539
				Some(location)
540
			}
541
		}
542
17
	}
543
}
544

            
545
parameter_types! {
546
	pub const BaseXcmWeight: Weight = Weight::from_parts(200_000_000u64, 0);
547
	pub const MaxAssetsForTransfer: usize = 2;
548

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

            
562
parameter_type_with_key! {
563
	pub ParachainMinFee: |location: Location| -> Option<u128> {
564
		match (location.parents, location.first_interior()) {
565
			// Polkadot AssetHub fee
566
			(1, Some(Parachain(1000u32))) => Some(50_000_000u128),
567
			_ => None,
568
		}
569
	};
570
}
571

            
572
impl orml_xtokens::Config for Runtime {
573
	type RuntimeEvent = RuntimeEvent;
574
	type Balance = Balance;
575
	type CurrencyId = CurrencyId;
576
	type AccountIdToLocation = AccountIdToLocation<AccountId>;
577
	type CurrencyIdConvert = CurrencyIdToLocation<AsAssetType<AssetId, AssetType, AssetManager>>;
578
	type XcmExecutor = XcmExecutor;
579
	type SelfLocation = SelfLocation;
580
	type Weigher = XcmWeigher;
581
	type BaseXcmWeight = BaseXcmWeight;
582
	type UniversalLocation = UniversalLocation;
583
	type MaxAssetsForTransfer = MaxAssetsForTransfer;
584
	type MinXcmFee = ParachainMinFee;
585
	type LocationsFilter = Everything;
586
	type ReserveProvider = AbsoluteAndRelativeReserve<SelfLocationAbsolute>;
587
	type RateLimiter = ();
588
	type RateLimiterId = ();
589
}
590

            
591
// 1 DOT should be enough
592
parameter_types! {
593
	pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into();
594
}
595

            
596
// For now we only allow to transact in the relay, although this might change in the future
597
// Transactors just defines the chains in which we allow transactions to be issued through
598
// xcm
599
6
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
600
pub enum Transactors {
601
	Relay,
602
}
603

            
604
// Default for benchmarking
605
#[cfg(feature = "runtime-benchmarks")]
606
impl Default for Transactors {
607
	fn default() -> Self {
608
		Transactors::Relay
609
	}
610
}
611

            
612
impl TryFrom<u8> for Transactors {
613
	type Error = ();
614
	fn try_from(value: u8) -> Result<Self, Self::Error> {
615
		match value {
616
			0u8 => Ok(Transactors::Relay),
617
			_ => Err(()),
618
		}
619
	}
620
}
621

            
622
impl UtilityEncodeCall for Transactors {
623
12
	fn encode_call(self, call: UtilityAvailableCalls) -> Vec<u8> {
624
12
		match self {
625
12
			Transactors::Relay => pallet_xcm_transactor::Pallet::<Runtime>::encode_call(
626
12
				pallet_xcm_transactor::Pallet(sp_std::marker::PhantomData::<Runtime>),
627
12
				call,
628
12
			),
629
12
		}
630
12
	}
631
}
632

            
633
impl XcmTransact for Transactors {
634
12
	fn destination(self) -> Location {
635
12
		match self {
636
12
			Transactors::Relay => Location::parent(),
637
12
		}
638
12
	}
639
}
640

            
641
pub type DerivativeAddressRegistrationOrigin =
642
	EitherOfDiverse<EnsureRoot<AccountId>, governance::custom_origins::GeneralAdmin>;
643

            
644
impl pallet_xcm_transactor::Config for Runtime {
645
	type RuntimeEvent = RuntimeEvent;
646
	type Balance = Balance;
647
	type Transactor = Transactors;
648
	type DerivativeAddressRegistrationOrigin = DerivativeAddressRegistrationOrigin;
649
	type SovereignAccountDispatcherOrigin = EnsureRoot<AccountId>;
650
	type CurrencyId = CurrencyId;
651
	type AccountIdToLocation = AccountIdToLocation<AccountId>;
652
	type CurrencyIdToLocation = CurrencyIdToLocation<AsAssetType<AssetId, AssetType, AssetManager>>;
653
	type XcmSender = XcmRouter;
654
	type SelfLocation = SelfLocation;
655
	type Weigher = XcmWeigher;
656
	type UniversalLocation = UniversalLocation;
657
	type BaseXcmWeight = BaseXcmWeight;
658
	type AssetTransactor = AssetTransactors;
659
	type ReserveProvider = AbsoluteAndRelativeReserve<SelfLocationAbsolute>;
660
	type WeightInfo = moonbeam_weights::pallet_xcm_transactor::WeightInfo<Runtime>;
661
	type HrmpManipulatorOrigin = GeneralAdminOrRoot;
662
	type HrmpOpenOrigin = FastGeneralAdminOrRoot;
663
	type MaxHrmpFee = xcm_builder::Case<MaxHrmpRelayFee>;
664
}
665

            
666
parameter_types! {
667
	// This is the relative view of erc20 assets.
668
	// Identified by this prefix + AccountKey20(contractAddress)
669
	// We use the RELATIVE multilocation
670
	pub Erc20XcmBridgePalletLocation: Location = Location {
671
		parents:0,
672
		interior: [
673
			PalletInstance(<Erc20XcmBridge as PalletInfoAccess>::index() as u8)
674
		].into()
675
	};
676

            
677
	// To be able to support almost all erc20 implementations,
678
	// we provide a sufficiently hight gas limit.
679
	pub Erc20XcmBridgeTransferGasLimit: u64 = 200_000;
680
}
681

            
682
impl pallet_erc20_xcm_bridge::Config for Runtime {
683
	type AccountIdConverter = LocationToH160;
684
	type Erc20MultilocationPrefix = Erc20XcmBridgePalletLocation;
685
	type Erc20TransferGasLimit = Erc20XcmBridgeTransferGasLimit;
686
	type EvmRunner = EvmRunnerPrecompileOrEthXcm<MoonbeamCall, Self>;
687
}
688

            
689
#[cfg(feature = "runtime-benchmarks")]
690
mod testing {
691
	use super::*;
692
	use xcm_builder::WithLatestLocationConverter;
693

            
694
	/// This From exists for benchmarking purposes. It has the potential side-effect of calling
695
	/// AssetManager::set_asset_type_asset_id() and should NOT be used in any production code.
696
	impl From<Location> for CurrencyId {
697
		fn from(location: Location) -> CurrencyId {
698
			use xcm_primitives::AssetTypeGetter;
699

            
700
			// If it does not exist, for benchmarking purposes, we create the association
701
			let asset_id = if let Some(asset_id) =
702
				AsAssetType::<AssetId, AssetType, AssetManager>::convert_location(&location)
703
			{
704
				asset_id
705
			} else {
706
				let asset_type = AssetType::Xcm(
707
					WithLatestLocationConverter::convert(&location).expect("convert to v3"),
708
				);
709
				let asset_id: AssetId = asset_type.clone().into();
710
				AssetManager::set_asset_type_asset_id(asset_type, asset_id);
711
				asset_id
712
			};
713

            
714
			CurrencyId::ForeignAsset(asset_id)
715
		}
716
	}
717
}