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 moonriver_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::Kusama;
80
	// The relay chain Origin type
81
	pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
82
	// The universal location within the global consensus system
83
	pub UniversalLocation: InteriorLocation =
84
		[GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into();
85

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

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

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

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

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

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

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

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

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

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

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

            
229
pub struct SafeCallFilter;
230
impl frame_support::traits::Contains<RuntimeCall> for SafeCallFilter {
231
	fn contains(_call: &RuntimeCall) -> bool {
232
		// TODO review
233
		// This needs to be addressed at EVM level
234
		true
235
	}
236
}
237

            
238
parameter_types! {
239
	/// Location of Asset Hub
240
	pub AssetHubLocation: Location = Location::new(1, [Parachain(1000)]);
241
	pub const RelayLocation: Location = Location::parent();
242
	pub RelayLocationFilter: AssetFilter = Wild(AllOf {
243
		fun: WildFungible,
244
		id: xcm::prelude::AssetId(RelayLocation::get()),
245
	});
246
	pub RelayChainNativeAssetFromAssetHub: (AssetFilter, Location) = (
247
		RelayLocationFilter::get(),
248
		AssetHubLocation::get()
249
	);
250
	pub const MaxAssetsIntoHolding: u32 = xcm_primitives::MAX_ASSETS;
251
}
252

            
253
type Reserves = (
254
	// Assets bridged from different consensus systems held in reserve on Asset Hub.
255
	IsBridgedConcreteAssetFrom<AssetHubLocation>,
256
	// Relaychain (DOT) from Asset Hub
257
	Case<RelayChainNativeAssetFromAssetHub>,
258
	// Assets which the reserve is the same as the origin.
259
	MultiNativeAsset<AbsoluteAndRelativeReserve<SelfLocationAbsolute>>,
260
);
261

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

            
269
moonbeam_runtime_common::impl_evm_runner_precompile_or_eth_xcm!();
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 = Reserves;
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 = pallet_xcm_weight_trader::Trader<Runtime>;
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
	type XcmRecorder = PolkadotXcm;
311
}
312

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

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

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

            
330
impl pallet_xcm::Config for Runtime {
331
	type RuntimeEvent = RuntimeEvent;
332
	type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
333
	type XcmRouter = XcmRouter;
334
	type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
335
	type XcmExecuteFilter = Nothing;
336
	type XcmExecutor = XcmExecutor;
337
	type XcmTeleportFilter = Nothing;
338
	type XcmReserveTransferFilter = Everything;
339
	type Weigher = XcmWeigher;
340
	type UniversalLocation = UniversalLocation;
341
	type RuntimeOrigin = RuntimeOrigin;
342
	type RuntimeCall = RuntimeCall;
343
	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
344
	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
345
	type Currency = Balances;
346
	type CurrencyMatcher = ();
347
	type TrustedLockers = ();
348
	type SovereignAccountOf = LocationToAccountId;
349
	type MaxLockers = ConstU32<8>;
350
	type MaxRemoteLockConsumers = ConstU32<0>;
351
	type RemoteLockConsumerIdentifier = ();
352
	type WeightInfo = moonriver_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 = moonriver_weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>;
370
	type PriceForSiblingDelivery = polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery<
371
		cumulus_primitives_core::ParaId,
372
	>;
373
	type MaxActiveOutboundChannels = ConstU32<128>;
374
	// Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we
375
	// need to set the page size larger than that until we reduce the channel size on-chain.
376
	type MaxPageSize = MessageQueueHeapSize;
377
}
378

            
379
parameter_types! {
380
	pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent;
381
}
382

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

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

            
425
pub type FastAuthorizeUpgradeOrigin = EitherOfDiverse<
426
	EnsureRoot<AccountId>,
427
	pallet_collective::EnsureProportionAtLeast<AccountId, OpenTechCommitteeInstance, 5, 9>,
428
>;
429

            
430
pub type ResumeXcmOrigin = EitherOfDiverse<
431
	EnsureRoot<AccountId>,
432
	pallet_collective::EnsureProportionAtLeast<AccountId, OpenTechCommitteeInstance, 5, 9>,
433
>;
434

            
435
impl pallet_emergency_para_xcm::Config for Runtime {
436
	type RuntimeEvent = RuntimeEvent;
437
	type CheckAssociatedRelayNumber =
438
		cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases;
439
	type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling<XcmpQueue>);
440
	type PausedThreshold = ConstU32<300>;
441
	type FastAuthorizeUpgradeOrigin = FastAuthorizeUpgradeOrigin;
442
	type PausedToNormalOrigin = ResumeXcmOrigin;
443
}
444

            
445
// Our AssetType. For now we only handle Xcm Assets
446
8
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
447
pub enum AssetType {
448
27
	Xcm(xcm::v3::Location),
449
}
450
impl Default for AssetType {
451
	fn default() -> Self {
452
		Self::Xcm(xcm::v3::Location::here())
453
	}
454
}
455

            
456
impl From<xcm::v3::Location> for AssetType {
457
576
	fn from(location: xcm::v3::Location) -> Self {
458
576
		Self::Xcm(location)
459
576
	}
460
}
461

            
462
// This can be removed once we fully adopt xcm::v4 everywhere
463
impl TryFrom<Location> for AssetType {
464
	type Error = ();
465
	fn try_from(location: Location) -> Result<Self, Self::Error> {
466
		Ok(Self::Xcm(location.try_into()?))
467
	}
468
}
469

            
470
impl Into<Option<xcm::v3::Location>> for AssetType {
471
176
	fn into(self) -> Option<xcm::v3::Location> {
472
176
		match self {
473
176
			Self::Xcm(location) => Some(location),
474
176
		}
475
176
	}
476
}
477

            
478
impl Into<Option<Location>> for AssetType {
479
	fn into(self) -> Option<Location> {
480
		match self {
481
			Self::Xcm(location) => {
482
				xcm_builder::WithLatestLocationConverter::convert_back(&location)
483
			}
484
		}
485
	}
486
}
487

            
488
// Implementation on how to retrieve the AssetId from an AssetType
489
// We simply hash the AssetType and take the lowest 128 bits
490
impl From<AssetType> for AssetId {
491
728
	fn from(asset: AssetType) -> AssetId {
492
728
		match asset {
493
728
			AssetType::Xcm(id) => {
494
728
				let mut result: [u8; 16] = [0u8; 16];
495
728
				let hash: H256 = id.using_encoded(<Runtime as frame_system::Config>::Hashing::hash);
496
728
				result.copy_from_slice(&hash.as_fixed_bytes()[0..16]);
497
728
				u128::from_le_bytes(result)
498
728
			}
499
728
		}
500
728
	}
501
}
502

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

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

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

            
566
parameter_types! {
567
	pub const BaseXcmWeight: Weight = Weight::from_parts(200_000_000u64, 0);
568
	pub const MaxAssetsForTransfer: usize = 2;
569

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

            
583
// 1 KSM should be enough
584
parameter_types! {
585
	pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into();
586
}
587

            
588
// For now we only allow to transact in the relay, although this might change in the future
589
// Transactors just defines the chains in which we allow transactions to be issued through
590
// xcm
591
8
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
592
pub enum Transactors {
593
	Relay,
594
}
595

            
596
// Default for benchmarking
597
#[cfg(feature = "runtime-benchmarks")]
598
impl Default for Transactors {
599
	fn default() -> Self {
600
		Transactors::Relay
601
	}
602
}
603

            
604
impl TryFrom<u8> for Transactors {
605
	type Error = ();
606
	fn try_from(value: u8) -> Result<Self, Self::Error> {
607
		match value {
608
			0u8 => Ok(Transactors::Relay),
609
			_ => Err(()),
610
		}
611
	}
612
}
613

            
614
impl UtilityEncodeCall for Transactors {
615
16
	fn encode_call(self, call: UtilityAvailableCalls) -> Vec<u8> {
616
16
		match self {
617
16
			Transactors::Relay => pallet_xcm_transactor::Pallet::<Runtime>::encode_call(
618
16
				pallet_xcm_transactor::Pallet(sp_std::marker::PhantomData::<Runtime>),
619
16
				call,
620
16
			),
621
16
		}
622
16
	}
623
}
624

            
625
impl XcmTransact for Transactors {
626
16
	fn destination(self) -> Location {
627
16
		match self {
628
16
			Transactors::Relay => Location::parent(),
629
16
		}
630
16
	}
631
}
632

            
633
pub type DerivativeAddressRegistrationOrigin =
634
	EitherOfDiverse<EnsureRoot<AccountId>, governance::custom_origins::GeneralAdmin>;
635

            
636
impl pallet_xcm_transactor::Config for Runtime {
637
	type RuntimeEvent = RuntimeEvent;
638
	type Balance = Balance;
639
	type Transactor = Transactors;
640
	type DerivativeAddressRegistrationOrigin = DerivativeAddressRegistrationOrigin;
641
	type SovereignAccountDispatcherOrigin = EnsureRoot<AccountId>;
642
	type CurrencyId = CurrencyId;
643
	type AccountIdToLocation = AccountIdToLocation<AccountId>;
644
	type CurrencyIdToLocation = CurrencyIdToLocation<AsAssetType<AssetId, AssetType, AssetManager>>;
645
	type XcmSender = XcmRouter;
646
	type SelfLocation = SelfLocation;
647
	type Weigher = XcmWeigher;
648
	type UniversalLocation = UniversalLocation;
649
	type BaseXcmWeight = BaseXcmWeight;
650
	type AssetTransactor = AssetTransactors;
651
	type ReserveProvider = AbsoluteAndRelativeReserve<SelfLocationAbsolute>;
652
	type WeightInfo = moonriver_weights::pallet_xcm_transactor::WeightInfo<Runtime>;
653
	type HrmpManipulatorOrigin = GeneralAdminOrRoot;
654
	type HrmpOpenOrigin = FastGeneralAdminOrRoot;
655
	type MaxHrmpFee = xcm_builder::Case<MaxHrmpRelayFee>;
656
}
657

            
658
parameter_types! {
659
	// This is the relative view of erc20 assets.
660
	// Identified by this prefix + AccountKey20(contractAddress)
661
	// We use the RELATIVE multilocation
662
	pub Erc20XcmBridgePalletLocation: Location = Location {
663
		parents:0,
664
		interior: [
665
			PalletInstance(<Erc20XcmBridge as PalletInfoAccess>::index() as u8)
666
		].into()
667
	};
668

            
669
	// To be able to support almost all erc20 implementations,
670
	// we provide a sufficiently hight gas limit.
671
	pub Erc20XcmBridgeTransferGasLimit: u64 = 800_000;
672
}
673

            
674
impl pallet_erc20_xcm_bridge::Config for Runtime {
675
	type AccountIdConverter = LocationToH160;
676
	type Erc20MultilocationPrefix = Erc20XcmBridgePalletLocation;
677
	type Erc20TransferGasLimit = Erc20XcmBridgeTransferGasLimit;
678
	type EvmRunner = EvmRunnerPrecompileOrEthXcm<MoonbeamCall, Self>;
679
}
680

            
681
pub struct AccountIdToH160;
682
impl sp_runtime::traits::Convert<AccountId, H160> for AccountIdToH160 {
683
	fn convert(account_id: AccountId) -> H160 {
684
		account_id.into()
685
	}
686
}
687

            
688
impl pallet_moonbeam_foreign_assets::Config for Runtime {
689
	type AccountIdToH160 = AccountIdToH160;
690
	type AssetIdFilter = Nothing;
691
	type EvmRunner = EvmRunnerPrecompileOrEthXcm<MoonbeamCall, Self>;
692
	type ForeignAssetCreatorOrigin = frame_system::EnsureNever<AccountId>;
693
	type ForeignAssetFreezerOrigin = frame_system::EnsureNever<AccountId>;
694
	type ForeignAssetModifierOrigin = frame_system::EnsureNever<AccountId>;
695
	type ForeignAssetUnfreezerOrigin = frame_system::EnsureNever<AccountId>;
696
	type OnForeignAssetCreated = ();
697
	type MaxForeignAssets = ConstU32<256>;
698
	type RuntimeEvent = RuntimeEvent;
699
	type WeightInfo = moonriver_weights::pallet_moonbeam_foreign_assets::WeightInfo<Runtime>;
700
	type XcmLocationToH160 = LocationToH160;
701
}
702

            
703
pub struct AssetFeesFilter;
704
impl frame_support::traits::Contains<Location> for AssetFeesFilter {
705
	fn contains(location: &Location) -> bool {
706
		location.parent_count() > 0
707
			&& location.first_interior() != Erc20XcmBridgePalletLocation::get().first_interior()
708
	}
709
}
710

            
711
pub type AddSupportedAssetOrigin = EitherOfDiverse<
712
	EnsureRoot<AccountId>,
713
	EitherOfDiverse<
714
		pallet_collective::EnsureProportionMoreThan<AccountId, OpenTechCommitteeInstance, 5, 9>,
715
		governance::custom_origins::GeneralAdmin,
716
	>,
717
>;
718

            
719
pub type EditSupportedAssetOrigin = EitherOfDiverse<
720
	EnsureRoot<AccountId>,
721
	EitherOfDiverse<
722
		pallet_collective::EnsureProportionMoreThan<AccountId, OpenTechCommitteeInstance, 5, 9>,
723
		governance::custom_origins::FastGeneralAdmin,
724
	>,
725
>;
726

            
727
pub type RemoveSupportedAssetOrigin = EitherOfDiverse<
728
	EnsureRoot<AccountId>,
729
	pallet_collective::EnsureProportionMoreThan<AccountId, OpenTechCommitteeInstance, 5, 9>,
730
>;
731

            
732
impl pallet_xcm_weight_trader::Config for Runtime {
733
	type AccountIdToLocation = AccountIdToLocation<AccountId>;
734
	type AddSupportedAssetOrigin = AddSupportedAssetOrigin;
735
	type AssetLocationFilter = AssetFeesFilter;
736
	type AssetTransactor = AssetTransactors;
737
	type Balance = Balance;
738
	type EditSupportedAssetOrigin = EditSupportedAssetOrigin;
739
	type NativeLocation = SelfReserve;
740
	type PauseSupportedAssetOrigin = EditSupportedAssetOrigin;
741
	type RemoveSupportedAssetOrigin = RemoveSupportedAssetOrigin;
742
	type RuntimeEvent = RuntimeEvent;
743
	type ResumeSupportedAssetOrigin = RemoveSupportedAssetOrigin;
744
	type WeightInfo = moonriver_weights::pallet_xcm_weight_trader::WeightInfo<Runtime>;
745
	type WeightToFee = <Runtime as pallet_transaction_payment::Config>::WeightToFee;
746
	type XcmFeesAccount = XcmFeesAccount;
747
	#[cfg(feature = "runtime-benchmarks")]
748
	type NotFilteredLocation = RelayLocation;
749
}
750

            
751
#[cfg(feature = "runtime-benchmarks")]
752
mod testing {
753
	use super::*;
754
	use xcm_builder::WithLatestLocationConverter;
755

            
756
	/// This From exists for benchmarking purposes. It has the potential side-effect of calling
757
	/// AssetManager::set_asset_type_asset_id() and should NOT be used in any production code.
758
	impl From<Location> for CurrencyId {
759
		fn from(location: Location) -> CurrencyId {
760
			use xcm_primitives::AssetTypeGetter;
761

            
762
			// If it does not exist, for benchmarking purposes, we create the association
763
			let asset_id = if let Some(asset_id) =
764
				AsAssetType::<AssetId, AssetType, AssetManager>::convert_location(&location)
765
			{
766
				asset_id
767
			} else {
768
				let asset_type = AssetType::Xcm(
769
					WithLatestLocationConverter::convert(&location).expect("convert to v3"),
770
				);
771
				let asset_id: AssetId = asset_type.clone().into();
772
				AssetManager::set_asset_type_asset_id(asset_type, asset_id);
773
				asset_id
774
			};
775

            
776
			CurrencyId::ForeignAsset(asset_id)
777
		}
778
	}
779
}