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,
22
	EmergencyParaXcm, Erc20XcmBridge, MaintenanceMode, MessageQueue, ParachainInfo,
23
	ParachainSystem, Perbill, PolkadotXcm, Runtime, RuntimeBlockWeights, RuntimeCall, RuntimeEvent,
24
	RuntimeOrigin, Treasury, XcmpQueue,
25
};
26
use crate::OpenTechCommitteeInstance;
27
use moonbeam_runtime_common::weights as moonbeam_weights;
28
use moonkit_xcm_primitives::AccountIdAssetIdConversion;
29
use sp_runtime::{
30
	traits::{Hash as THash, MaybeEquivalence, PostDispatchInfoOf},
31
	DispatchErrorWithPostInfo,
32
};
33

            
34
use frame_support::{
35
	parameter_types,
36
	traits::{EitherOfDiverse, Everything, Nothing, PalletInfoAccess, TransformOrigin},
37
};
38

            
39
use frame_system::{EnsureRoot, RawOrigin};
40
use sp_core::{ConstU32, H160, H256};
41
use sp_weights::Weight;
42
use xcm_builder::{
43
	AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
44
	AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, DescribeAllTerminal, DescribeFamily,
45
	EnsureXcmOrigin, FungibleAdapter as XcmCurrencyAdapter, FungiblesAdapter, HashedDescription,
46
	NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
47
	SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation,
48
	TakeWeightCredit, UsingComponents, WeightInfoBounds, WithComputedOrigin,
49
};
50

            
51
use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling};
52

            
53
use xcm::latest::prelude::{
54
	Asset, GlobalConsensus, InteriorLocation, Junction, Location, NetworkId, PalletInstance,
55
	Parachain,
56
};
57
use xcm_executor::traits::{CallDispatcher, ConvertLocation, JustTry};
58

            
59
use cumulus_primitives_core::{AggregateMessageOrigin, ParaId};
60
use orml_xcm_support::MultiNativeAsset;
61
use xcm_primitives::{
62
	AbsoluteAndRelativeReserve, AccountIdToCurrencyId, AccountIdToLocation, AsAssetType,
63
	FirstAssetTrader, SignedToAccountId20, UtilityAvailableCalls, 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 orml_traits::parameter_type_with_key;
76

            
77
use crate::governance::referenda::{FastGeneralAdminOrRoot, GeneralAdminOrRoot};
78

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

            
88

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

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

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

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

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

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

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

            
197
parameter_types! {
198
	/// Maximum number of instructions in a single XCM fragment. A sanity check against
199
	/// weight caculations getting too crazy.
200
	pub MaxInstructions: u32 = 100;
201
}
202

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

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

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

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

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

            
256
moonbeam_runtime_common::impl_evm_runner_precompile_or_eth_xcm!();
257

            
258
pub struct SafeCallFilter;
259
impl frame_support::traits::Contains<RuntimeCall> for SafeCallFilter {
260
	fn contains(_call: &RuntimeCall) -> bool {
261
		// TODO review
262
		// This needs to be addressed at EVM level
263
		true
264
	}
265
}
266

            
267
parameter_types! {
268
	pub const MaxAssetsIntoHolding: u32 = xcm_primitives::MAX_ASSETS;
269
}
270

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

            
321
// Converts a Signed Local Origin into a Location
322
pub type LocalOriginToLocation = SignedToAccountId20<RuntimeOrigin, AccountId, RelayNetwork>;
323

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

            
333
type XcmExecutor = pallet_erc20_xcm_bridge::XcmExecutorWrapper<
334
	XcmExecutorConfig,
335
	xcm_executor::XcmExecutor<XcmExecutorConfig>,
336
>;
337

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

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

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

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

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

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

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

            
438
impl pallet_emergency_para_xcm::Config for Runtime {
439
	type RuntimeEvent = RuntimeEvent;
440
	type CheckAssociatedRelayNumber =
441
		cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases;
442
	type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling<XcmpQueue>);
443
	type XcmpMessageHandler = XcmpQueue;
444
	type PausedThreshold = ConstU32<300>;
445
	type FastAuthorizeUpgradeOrigin =
446
		pallet_collective::EnsureProportionAtLeast<AccountId, OpenTechCommitteeInstance, 5, 9>;
447
	type PausedToNormalOrigin =
448
		pallet_collective::EnsureProportionAtLeast<AccountId, OpenTechCommitteeInstance, 5, 9>;
449
}
450

            
451
// Our AssetType. For now we only handle Xcm Assets
452
8
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
453
pub enum AssetType {
454
75
	Xcm(xcm::v3::Location),
455
}
456
impl Default for AssetType {
457
	fn default() -> Self {
458
		Self::Xcm(xcm::v3::Location::here())
459
	}
460
}
461

            
462
impl From<xcm::v3::Location> for AssetType {
463
424
	fn from(location: xcm::v3::Location) -> Self {
464
424
		Self::Xcm(location)
465
424
	}
466
}
467

            
468
// This can be removed once we fully adopt xcm::v4 everywhere
469
impl TryFrom<Location> for AssetType {
470
	type Error = ();
471
232
	fn try_from(location: Location) -> Result<Self, Self::Error> {
472
232
		Ok(Self::Xcm(location.try_into()?))
473
232
	}
474
}
475

            
476
impl Into<Option<xcm::v3::Location>> for AssetType {
477
144
	fn into(self) -> Option<xcm::v3::Location> {
478
144
		match self {
479
144
			Self::Xcm(location) => Some(location),
480
144
		}
481
144
	}
482
}
483

            
484
impl Into<Option<Location>> for AssetType {
485
	fn into(self) -> Option<Location> {
486
		match self {
487
			Self::Xcm(location) => {
488
				xcm_builder::WithLatestLocationConverter::convert_back(&location)
489
			}
490
		}
491
	}
492
}
493

            
494
// Implementation on how to retrieve the AssetId from an AssetType
495
// We take it
496
impl From<AssetType> for AssetId {
497
592
	fn from(asset: AssetType) -> AssetId {
498
592
		match asset {
499
592
			AssetType::Xcm(id) => {
500
592
				let mut result: [u8; 16] = [0u8; 16];
501
592
				let hash: H256 = id.using_encoded(<Runtime as frame_system::Config>::Hashing::hash);
502
592
				result.copy_from_slice(&hash.as_fixed_bytes()[0..16]);
503
592
				u128::from_le_bytes(result)
504
592
			}
505
592
		}
506
592
	}
507
}
508

            
509
// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id.
510
24
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
511
pub enum CurrencyId {
512
	// Our native token
513
	SelfReserve,
514
	// Assets representing other chains native tokens
515
	ForeignAsset(AssetId),
516
	// Erc20 token
517
	Erc20 { contract_address: H160 },
518
}
519

            
520
impl AccountIdToCurrencyId<AccountId, CurrencyId> for Runtime {
521
16
	fn account_to_currency_id(account: AccountId) -> Option<CurrencyId> {
522
16
		Some(match account {
523
			// the self-reserve currency is identified by the pallet-balances address
524
16
			a if a == H160::from_low_u64_be(2050).into() => CurrencyId::SelfReserve,
525
			// the rest of the currencies, by their corresponding erc20 address
526
8
			_ => match Runtime::account_to_asset_id(account) {
527
				// A foreign asset
528
8
				Some((_prefix, asset_id)) => CurrencyId::ForeignAsset(asset_id),
529
				// If no known prefix is identified, we consider that it's a "real" erc20 token
530
				// (i.e. managed by a real smart contract)
531
				None => CurrencyId::Erc20 {
532
					contract_address: account.into(),
533
				},
534
			},
535
		})
536
16
	}
537
}
538

            
539
// How to convert from CurrencyId to Location
540
pub struct CurrencyIdToLocation<AssetXConverter>(sp_std::marker::PhantomData<AssetXConverter>);
541
impl<AssetXConverter> sp_runtime::traits::Convert<CurrencyId, Option<Location>>
542
	for CurrencyIdToLocation<AssetXConverter>
543
where
544
	AssetXConverter: MaybeEquivalence<Location, AssetId>,
545
{
546
35
	fn convert(currency: CurrencyId) -> Option<Location> {
547
35
		match currency {
548
			CurrencyId::SelfReserve => {
549
16
				let multi: Location = SelfReserve::get();
550
16
				Some(multi)
551
			}
552
19
			CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset),
553
			CurrencyId::Erc20 { contract_address } => {
554
				let mut location = Erc20XcmBridgePalletLocation::get();
555
				location
556
					.push_interior(Junction::AccountKey20 {
557
						key: contract_address.0,
558
						network: None,
559
					})
560
					.ok();
561
				Some(location)
562
			}
563
		}
564
35
	}
565
}
566

            
567
parameter_types! {
568
	pub const BaseXcmWeight: Weight
569
		= Weight::from_parts(200_000_000u64, 0);
570
	pub const MaxAssetsForTransfer: usize = 2;
571
	// This is how we are going to detect whether the asset is a Reserve asset
572
	// This however is the chain part only
573
	pub SelfLocation: Location = Location::here();
574
	// We need this to be able to catch when someone is trying to execute a non-
575
	// cross-chain transfer in xtokens through the absolute path way
576
	pub SelfLocationAbsolute: Location = Location {
577
		parents:1,
578
		interior: [
579
			Parachain(ParachainInfo::parachain_id().into())
580
		].into()
581
	};
582

            
583
}
584

            
585
parameter_type_with_key! {
586
	pub ParachainMinFee: |location: Location| -> Option<u128> {
587
		match (location.parents, location.first_interior()) {
588
			// AssetHub fee
589
			(1, Some(Parachain(1001u32))) => Some(50_000_000u128),
590
			_ => None,
591
		}
592
	};
593
}
594

            
595
impl orml_xtokens::Config for Runtime {
596
	type RuntimeEvent = RuntimeEvent;
597
	type Balance = Balance;
598
	type CurrencyId = CurrencyId;
599
	type AccountIdToLocation = AccountIdToLocation<AccountId>;
600
	type CurrencyIdConvert = CurrencyIdToLocation<AsAssetType<AssetId, AssetType, AssetManager>>;
601
	type XcmExecutor = XcmExecutor;
602
	type SelfLocation = SelfLocation;
603
	type Weigher = XcmWeigher;
604
	type BaseXcmWeight = BaseXcmWeight;
605
	type UniversalLocation = UniversalLocation;
606
	type MaxAssetsForTransfer = MaxAssetsForTransfer;
607
	type MinXcmFee = ParachainMinFee;
608
	type LocationsFilter = Everything;
609
	type ReserveProvider = AbsoluteAndRelativeReserve<SelfLocationAbsolute>;
610
	type RateLimiter = ();
611
	type RateLimiterId = ();
612
}
613

            
614
// 1 WND/ROC should be enough
615
parameter_types! {
616
	pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into();
617
}
618

            
619
// For now we only allow to transact in the relay, although this might change in the future
620
// Transactors just defines the chains in which we allow transactions to be issued through
621
// xcm
622
8
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
623
pub enum Transactors {
624
	Relay,
625
}
626

            
627
// Default for benchmarking
628
#[cfg(feature = "runtime-benchmarks")]
629
impl Default for Transactors {
630
	fn default() -> Self {
631
		Transactors::Relay
632
	}
633
}
634

            
635
impl TryFrom<u8> for Transactors {
636
	type Error = ();
637
	fn try_from(value: u8) -> Result<Self, Self::Error> {
638
		match value {
639
			0u8 => Ok(Transactors::Relay),
640
			_ => Err(()),
641
		}
642
	}
643
}
644

            
645
impl UtilityEncodeCall for Transactors {
646
16
	fn encode_call(self, call: UtilityAvailableCalls) -> Vec<u8> {
647
16
		match self {
648
16
			Transactors::Relay => pallet_xcm_transactor::Pallet::<Runtime>::encode_call(
649
16
				pallet_xcm_transactor::Pallet(sp_std::marker::PhantomData::<Runtime>),
650
16
				call,
651
16
			),
652
16
		}
653
16
	}
654
}
655

            
656
impl XcmTransact for Transactors {
657
16
	fn destination(self) -> Location {
658
16
		match self {
659
16
			Transactors::Relay => Location::parent(),
660
16
		}
661
16
	}
662
}
663

            
664
pub type DerivativeAddressRegistrationOrigin =
665
	EitherOfDiverse<EnsureRoot<AccountId>, governance::custom_origins::GeneralAdmin>;
666

            
667
impl pallet_xcm_transactor::Config for Runtime {
668
	type RuntimeEvent = RuntimeEvent;
669
	type Balance = Balance;
670
	type Transactor = Transactors;
671
	type DerivativeAddressRegistrationOrigin = DerivativeAddressRegistrationOrigin;
672
	type SovereignAccountDispatcherOrigin = EnsureRoot<AccountId>;
673
	type CurrencyId = CurrencyId;
674
	type AccountIdToLocation = AccountIdToLocation<AccountId>;
675
	type CurrencyIdToLocation = CurrencyIdToLocation<AsAssetType<AssetId, AssetType, AssetManager>>;
676
	type XcmSender = XcmRouter;
677
	type SelfLocation = SelfLocation;
678
	type Weigher = XcmWeigher;
679
	type UniversalLocation = UniversalLocation;
680
	type BaseXcmWeight = BaseXcmWeight;
681
	type AssetTransactor = AssetTransactors;
682
	type ReserveProvider = AbsoluteAndRelativeReserve<SelfLocationAbsolute>;
683
	type WeightInfo = moonbeam_weights::pallet_xcm_transactor::WeightInfo<Runtime>;
684
	type HrmpManipulatorOrigin = GeneralAdminOrRoot;
685
	type HrmpOpenOrigin = FastGeneralAdminOrRoot;
686
	type MaxHrmpFee = xcm_builder::Case<MaxHrmpRelayFee>;
687
}
688

            
689
parameter_types! {
690
	// This is the relative view of erc20 assets.
691
	// Identified by this prefix + AccountKey20(contractAddress)
692
	// We use the RELATIVE multilocation
693
	pub Erc20XcmBridgePalletLocation: Location = Location {
694
		parents:0,
695
		interior: [
696
			PalletInstance(<Erc20XcmBridge as PalletInfoAccess>::index() as u8)
697
		].into()
698
	};
699

            
700
	// To be able to support almost all erc20 implementations,
701
	// we provide a sufficiently hight gas limit.
702
	pub Erc20XcmBridgeTransferGasLimit: u64 = 800_000;
703
}
704

            
705
impl pallet_erc20_xcm_bridge::Config for Runtime {
706
	type AccountIdConverter = LocationToH160;
707
	type Erc20MultilocationPrefix = Erc20XcmBridgePalletLocation;
708
	type Erc20TransferGasLimit = Erc20XcmBridgeTransferGasLimit;
709
	type EvmRunner = EvmRunnerPrecompileOrEthXcm<MoonbeamCall, Self>;
710
}
711

            
712
#[cfg(feature = "runtime-benchmarks")]
713
mod testing {
714
	use super::*;
715
	use xcm_builder::WithLatestLocationConverter;
716

            
717
	/// This From exists for benchmarking purposes. It has the potential side-effect of calling
718
	/// AssetManager::set_asset_type_asset_id() and should NOT be used in any production code.
719
	impl From<Location> for CurrencyId {
720
		fn from(location: Location) -> CurrencyId {
721
			use xcm_primitives::AssetTypeGetter;
722

            
723
			// If it does not exist, for benchmarking purposes, we create the association
724
			let asset_id = if let Some(asset_id) =
725
				AsAssetType::<AssetId, AssetType, AssetManager>::convert_location(&location)
726
			{
727
				asset_id
728
			} else {
729
				let asset_type = AssetType::Xcm(
730
					WithLatestLocationConverter::convert(&location).expect("convert to v3"),
731
				);
732
				let asset_id: AssetId = asset_type.clone().into();
733
				AssetManager::set_asset_type_asset_id(asset_type, asset_id);
734
				asset_id
735
			};
736

            
737
			CurrencyId::ForeignAsset(asset_id)
738
		}
739
	}
740
}