1
// Copyright 2019-2025 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, EvmForeignAssets, MaintenanceMode, MessageQueue, OpenTechCommitteeInstance,
23
	ParachainInfo, ParachainSystem, Perbill, PolkadotXcm, Runtime, RuntimeBlockWeights,
24
	RuntimeCall, RuntimeEvent, RuntimeOrigin, Treasury, XcmpQueue,
25
};
26

            
27
use super::moonriver_weights;
28
use frame_support::{
29
	parameter_types,
30
	traits::{EitherOf, EitherOfDiverse, Everything, Nothing, PalletInfoAccess, TransformOrigin},
31
};
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, TrailingSetTopicAsId, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
49
};
50

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

            
60
use xcm_executor::traits::{CallDispatcher, ConvertLocation, JustTry};
61

            
62
use cumulus_primitives_core::{AggregateMessageOrigin, ParaId};
63
use pallet_xcm::EnsureXcm;
64
use xcm_primitives::{
65
	AbsoluteAndRelativeReserve, AccountIdToCurrencyId, AccountIdToLocation, AsAssetType,
66
	IsBridgedConcreteAssetFrom, MultiNativeAsset, SignedToAccountId20, UtilityAvailableCalls,
67
	UtilityEncodeCall, XcmTransact,
68
};
69

            
70
use crate::governance::referenda::{FastGeneralAdminOrRoot, GeneralAdminOrRoot};
71
use crate::runtime_params::dynamic_params;
72
use moonbeam_runtime_common::xcm_origins::AllowSiblingParachains;
73
use pallet_moonbeam_foreign_assets::{MapSuccessToGovernance, MapSuccessToXcm};
74
use parity_scale_codec::{Decode, Encode};
75
use scale_info::TypeInfo;
76
use sp_core::Get;
77
use sp_std::{
78
	convert::{From, Into, TryFrom},
79
	prelude::*,
80
};
81

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

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

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

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

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

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

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

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

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

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

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

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

            
235
pub struct SafeCallFilter;
236
impl frame_support::traits::Contains<RuntimeCall> for SafeCallFilter {
237
	fn contains(_call: &RuntimeCall) -> bool {
238
		// TODO review
239
		// This needs to be addressed at EVM level
240
		true
241
	}
242
}
243

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

            
259
type Reserves = (
260
	// Assets bridged from different consensus systems held in reserve on Asset Hub.
261
	IsBridgedConcreteAssetFrom<AssetHubLocation>,
262
	// Relaychain (DOT) from Asset Hub
263
	Case<RelayChainNativeAssetFromAssetHub>,
264
	// Assets which the reserve is the same as the origin.
265
	MultiNativeAsset<AbsoluteAndRelativeReserve<SelfLocationAbsolute>>,
266
);
267

            
268
// Our implementation of the Moonbeam Call
269
// Attachs the right origin in case the call is made to pallet-ethereum-xcm
270
#[cfg(not(feature = "evm-tracing"))]
271
moonbeam_runtime_common::impl_moonbeam_xcm_call!();
272
#[cfg(feature = "evm-tracing")]
273
moonbeam_runtime_common::impl_moonbeam_xcm_call_tracing!();
274

            
275
moonbeam_runtime_common::impl_evm_runner_precompile_or_eth_xcm!();
276

            
277
pub struct XcmExecutorConfig;
278
impl xcm_executor::Config for XcmExecutorConfig {
279
	type RuntimeCall = RuntimeCall;
280
	type XcmSender = XcmRouter;
281
	// How to withdraw and deposit an asset.
282
	type AssetTransactor = AssetTransactors;
283
	type OriginConverter = XcmOriginToTransactDispatchOrigin;
284
	// Filter to the reserve withdraw operations
285
	// Whenever the reserve matches the relative or absolute value
286
	// of our chain, we always return the relative reserve
287
	type IsReserve = Reserves;
288
	type IsTeleporter = (); // No teleport
289
	type UniversalLocation = UniversalLocation;
290
	type Barrier = XcmBarrier;
291
	type Weigher = XcmWeigher;
292
	// As trader we use the XcmWeightTrader pallet.
293
	// For each foreign asset, the fee is computed based on its relative price (also
294
	// stored in the XcmWeightTrader pallet) against the native asset.
295
	// For the native asset fee is computed using WeightToFee implementation.
296
	type Trader = pallet_xcm_weight_trader::Trader<Runtime>;
297
	type ResponseHandler = PolkadotXcm;
298
	type SubscriptionService = PolkadotXcm;
299
	type AssetTrap = pallet_erc20_xcm_bridge::AssetTrapWrapper<PolkadotXcm, Runtime>;
300
	type AssetClaims = PolkadotXcm;
301
	type CallDispatcher = MoonbeamCall;
302
	type PalletInstancesInfo = crate::AllPalletsWithSystem;
303
	type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
304
	type AssetLocker = ();
305
	type AssetExchanger = ();
306
	type FeeManager = ();
307
	type MessageExporter = ();
308
	type UniversalAliases = Nothing;
309
	type SafeCallFilter = SafeCallFilter;
310
	type Aliasers = Nothing;
311
	type TransactionalProcessor = xcm_builder::FrameTransactionalProcessor;
312
	type HrmpNewChannelOpenRequestHandler = ();
313
	type HrmpChannelAcceptedHandler = ();
314
	type HrmpChannelClosingHandler = ();
315
	type XcmRecorder = PolkadotXcm;
316
}
317

            
318
type XcmExecutor = pallet_erc20_xcm_bridge::XcmExecutorWrapper<
319
	XcmExecutorConfig,
320
	xcm_executor::XcmExecutor<XcmExecutorConfig>,
321
>;
322

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

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

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

            
361
impl cumulus_pallet_xcm::Config for Runtime {
362
	type RuntimeEvent = RuntimeEvent;
363
	type XcmExecutor = XcmExecutor;
364
}
365

            
366
impl cumulus_pallet_xcmp_queue::Config for Runtime {
367
	type RuntimeEvent = RuntimeEvent;
368
	type ChannelInfo = ParachainSystem;
369
	type VersionWrapper = PolkadotXcm;
370
	type XcmpQueue = TransformOrigin<MessageQueue, AggregateMessageOrigin, ParaId, ParaIdToSibling>;
371
	type MaxInboundSuspended = sp_core::ConstU32<1_000>;
372
	type ControllerOrigin = EnsureRoot<AccountId>;
373
	type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
374
	type WeightInfo = moonriver_weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>;
375
	type PriceForSiblingDelivery = polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery<
376
		cumulus_primitives_core::ParaId,
377
	>;
378
	type MaxActiveOutboundChannels = ConstU32<128>;
379
	// Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we
380
	// need to set the page size larger than that until we reduce the channel size on-chain.
381
	type MaxPageSize = MessageQueueHeapSize;
382
}
383

            
384
parameter_types! {
385
	pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent;
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 = 103 * 1024;
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 = pallet_ethereum_xcm::MessageProcessorWrapper<
416
		xcm_builder::ProcessXcmMessage<AggregateMessageOrigin, XcmExecutor, RuntimeCall>,
417
	>;
418
	type Size = u32;
419
	type HeapSize = MessageQueueHeapSize;
420
	type MaxStale = MessageQueueMaxStale;
421
	type ServiceWeight = MessageQueueServiceWeight;
422
	// The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin:
423
	type QueueChangeHandler = NarrowOriginToSibling<XcmpQueue>;
424
	// NarrowOriginToSibling calls XcmpQueue's is_paused if Origin is sibling. Allows all other origins
425
	type QueuePausedQuery = EmergencyParaXcm;
426
	type WeightInfo = moonriver_weights::pallet_message_queue::WeightInfo<Runtime>;
427
	type IdleMaxServiceWeight = MessageQueueServiceWeight;
428
}
429

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

            
435
pub type ResumeXcmOrigin = EitherOfDiverse<
436
	EnsureRoot<AccountId>,
437
	pallet_collective::EnsureProportionAtLeast<AccountId, OpenTechCommitteeInstance, 5, 9>,
438
>;
439

            
440
impl pallet_emergency_para_xcm::Config for Runtime {
441
	type RuntimeEvent = RuntimeEvent;
442
	type CheckAssociatedRelayNumber =
443
		cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases;
444
	type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling<XcmpQueue>);
445
	type PausedThreshold = ConstU32<300>;
446
	type FastAuthorizeUpgradeOrigin = FastAuthorizeUpgradeOrigin;
447
	type PausedToNormalOrigin = ResumeXcmOrigin;
448
}
449

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

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

            
467
// This can be removed once we fully adopt xcm::v5 everywhere
468
impl TryFrom<Location> for AssetType {
469
	type Error = ();
470

            
471
77
	fn try_from(location: Location) -> Result<Self, Self::Error> {
472
77
		// Convert the V5 location to a V3 location
473
77
		match xcm::VersionedLocation::V5(location).into_version(xcm::v3::VERSION) {
474
77
			Ok(xcm::VersionedLocation::V3(loc)) => Ok(AssetType::Xcm(loc.into())),
475
			// Any other version or conversion error returns an error
476
			_ => Err(()),
477
		}
478
77
	}
479
}
480

            
481
impl Into<Option<xcm::v3::Location>> for AssetType {
482
154
	fn into(self) -> Option<xcm::v3::Location> {
483
154
		match self {
484
154
			Self::Xcm(location) => Some(location),
485
154
		}
486
154
	}
487
}
488

            
489
impl Into<Option<Location>> for AssetType {
490
	fn into(self) -> Option<Location> {
491
		match self {
492
			Self::Xcm(location) => {
493
				let versioned = xcm::VersionedLocation::V3(location);
494
				match versioned.into_version(xcm::latest::VERSION) {
495
					Ok(xcm::VersionedLocation::V5(loc)) => Some(loc),
496
					_ => None,
497
				}
498
			}
499
		}
500
	}
501
}
502

            
503
// Implementation on how to retrieve the AssetId from an AssetType
504
// We simply hash the AssetType and take the lowest 128 bits
505
impl From<AssetType> for AssetId {
506
658
	fn from(asset: AssetType) -> AssetId {
507
658
		match asset {
508
658
			AssetType::Xcm(id) => {
509
658
				let mut result: [u8; 16] = [0u8; 16];
510
658
				let hash: H256 = id.using_encoded(<Runtime as frame_system::Config>::Hashing::hash);
511
658
				result.copy_from_slice(&hash.as_fixed_bytes()[0..16]);
512
658
				u128::from_le_bytes(result)
513
658
			}
514
658
		}
515
658
	}
516
}
517

            
518
// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id.
519
21
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
520
pub enum CurrencyId {
521
	// Our native token
522
	SelfReserve,
523
	// Assets representing other chains native tokens
524
	ForeignAsset(AssetId),
525
	// Erc20 token
526
	Erc20 { contract_address: H160 },
527
}
528

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

            
548
// How to convert from CurrencyId to Location
549
pub struct CurrencyIdToLocation<AssetXConverter>(sp_std::marker::PhantomData<AssetXConverter>);
550
impl<AssetXConverter> sp_runtime::traits::Convert<CurrencyId, Option<Location>>
551
	for CurrencyIdToLocation<AssetXConverter>
552
where
553
	AssetXConverter: MaybeEquivalence<Location, AssetId>,
554
{
555
6
	fn convert(currency: CurrencyId) -> Option<Location> {
556
6
		match currency {
557
			// For now and until Xtokens is adapted to handle 0.9.16 version we use
558
			// the old anchoring here
559
			// This is not a problem in either cases, since the view of the destination
560
			// chain does not change
561
			// TODO! change this to NewAnchoringSelfReserve once xtokens is adapted for it
562
			CurrencyId::SelfReserve => {
563
				let multi: Location = SelfReserve::get();
564
				Some(multi)
565
			}
566
6
			CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset),
567
			CurrencyId::Erc20 { contract_address } => {
568
				let mut location = Erc20XcmBridgePalletLocation::get();
569
				location
570
					.push_interior(Junction::AccountKey20 {
571
						key: contract_address.0,
572
						network: None,
573
					})
574
					.ok();
575
				Some(location)
576
			}
577
		}
578
6
	}
579
}
580

            
581
parameter_types! {
582
	pub const BaseXcmWeight: Weight = Weight::from_parts(200_000_000u64, 0);
583
	pub const MaxAssetsForTransfer: usize = 2;
584

            
585
	// This is how we are going to detect whether the asset is a Reserve asset
586
	// This however is the chain part only
587
	pub SelfLocation: Location = Location::here();
588
	// We need this to be able to catch when someone is trying to execute a non-
589
	// cross-chain transfer in xtokens through the absolute path way
590
	pub SelfLocationAbsolute: Location = Location {
591
		parents:1,
592
		interior: [
593
			Parachain(ParachainInfo::parachain_id().into())
594
		].into()
595
	};
596
}
597

            
598
// 1 KSM should be enough
599
parameter_types! {
600
	pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into();
601
}
602

            
603
// For now we only allow to transact in the relay, although this might change in the future
604
// Transactors just defines the chains in which we allow transactions to be issued through
605
// xcm
606
7
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
607
pub enum Transactors {
608
	Relay,
609
}
610

            
611
// Default for benchmarking
612
#[cfg(feature = "runtime-benchmarks")]
613
impl Default for Transactors {
614
	fn default() -> Self {
615
		Transactors::Relay
616
	}
617
}
618

            
619
impl TryFrom<u8> for Transactors {
620
	type Error = ();
621
	fn try_from(value: u8) -> Result<Self, Self::Error> {
622
		match value {
623
			0u8 => Ok(Transactors::Relay),
624
			_ => Err(()),
625
		}
626
	}
627
}
628

            
629
impl UtilityEncodeCall for Transactors {
630
14
	fn encode_call(self, call: UtilityAvailableCalls) -> Vec<u8> {
631
14
		match self {
632
14
			Transactors::Relay => pallet_xcm_transactor::Pallet::<Runtime>::encode_call(
633
14
				pallet_xcm_transactor::Pallet(sp_std::marker::PhantomData::<Runtime>),
634
14
				call,
635
14
			),
636
14
		}
637
14
	}
638
}
639

            
640
impl XcmTransact for Transactors {
641
14
	fn destination(self) -> Location {
642
14
		match self {
643
14
			Transactors::Relay => Location::parent(),
644
14
		}
645
14
	}
646
}
647

            
648
pub type DerivativeAddressRegistrationOrigin =
649
	EitherOfDiverse<EnsureRoot<AccountId>, governance::custom_origins::GeneralAdmin>;
650

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

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

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

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

            
699
pub struct AccountIdToH160;
700
impl sp_runtime::traits::Convert<AccountId, H160> for AccountIdToH160 {
701
126
	fn convert(account_id: AccountId) -> H160 {
702
126
		account_id.into()
703
126
	}
704
}
705

            
706
pub struct EvmForeignAssetIdFilter;
707
impl frame_support::traits::Contains<AssetId> for EvmForeignAssetIdFilter {
708
14
	fn contains(asset_id: &AssetId) -> bool {
709
		use xcm_primitives::AssetTypeGetter as _;
710
		// We should return true only if the AssetId doesn't exist in AssetManager
711
14
		AssetManager::get_asset_type(*asset_id).is_none()
712
14
	}
713
}
714

            
715
pub type ForeignAssetManagerOrigin = EitherOf<
716
	MapSuccessToXcm<EnsureXcm<AllowSiblingParachains>>,
717
	MapSuccessToGovernance<
718
		EitherOf<
719
			EnsureRoot<AccountId>,
720
			EitherOf<
721
				pallet_collective::EnsureProportionMoreThan<
722
					AccountId,
723
					OpenTechCommitteeInstance,
724
					5,
725
					9,
726
				>,
727
				EitherOf<
728
					governance::custom_origins::FastGeneralAdmin,
729
					governance::custom_origins::GeneralAdmin,
730
				>,
731
			>,
732
		>,
733
	>,
734
>;
735
impl pallet_moonbeam_foreign_assets::Config for Runtime {
736
	type AccountIdToH160 = AccountIdToH160;
737
	type AssetIdFilter = EvmForeignAssetIdFilter;
738
	type EvmRunner = EvmRunnerPrecompileOrEthXcm<MoonbeamCall, Self>;
739
	type ConvertLocation =
740
		SiblingParachainConvertsVia<polkadot_parachain::primitives::Sibling, AccountId>;
741
	type ForeignAssetCreatorOrigin = ForeignAssetManagerOrigin;
742
	type ForeignAssetFreezerOrigin = ForeignAssetManagerOrigin;
743
	type ForeignAssetModifierOrigin = ForeignAssetManagerOrigin;
744
	type ForeignAssetUnfreezerOrigin = ForeignAssetManagerOrigin;
745
	type OnForeignAssetCreated = ();
746
	type MaxForeignAssets = ConstU32<256>;
747
	type RuntimeEvent = RuntimeEvent;
748
	type WeightInfo = moonriver_weights::pallet_moonbeam_foreign_assets::WeightInfo<Runtime>;
749
	type XcmLocationToH160 = LocationToH160;
750
	type ForeignAssetCreationDeposit = dynamic_params::xcm_config::ForeignAssetCreationDeposit;
751
	type Currency = Balances;
752
	type Balance = Balance;
753
}
754

            
755
pub struct AssetFeesFilter;
756
impl frame_support::traits::Contains<Location> for AssetFeesFilter {
757
7
	fn contains(location: &Location) -> bool {
758
7
		location.parent_count() > 0
759
7
			&& location.first_interior() != Erc20XcmBridgePalletLocation::get().first_interior()
760
7
	}
761
}
762

            
763
pub type AddAndEditSupportedAssetOrigin = EitherOfDiverse<
764
	EnsureRoot<AccountId>,
765
	EitherOfDiverse<
766
		pallet_collective::EnsureProportionMoreThan<AccountId, OpenTechCommitteeInstance, 5, 9>,
767
		EitherOf<
768
			governance::custom_origins::GeneralAdmin,
769
			governance::custom_origins::FastGeneralAdmin,
770
		>,
771
	>,
772
>;
773

            
774
pub type RemoveSupportedAssetOrigin = EitherOfDiverse<
775
	EnsureRoot<AccountId>,
776
	pallet_collective::EnsureProportionMoreThan<AccountId, OpenTechCommitteeInstance, 5, 9>,
777
>;
778

            
779
impl pallet_xcm_weight_trader::Config for Runtime {
780
	type AccountIdToLocation = AccountIdToLocation<AccountId>;
781
	type AddSupportedAssetOrigin = AddAndEditSupportedAssetOrigin;
782
	type AssetLocationFilter = AssetFeesFilter;
783
	type AssetTransactor = AssetTransactors;
784
	type Balance = Balance;
785
	type EditSupportedAssetOrigin = AddAndEditSupportedAssetOrigin;
786
	type NativeLocation = SelfReserve;
787
	type PauseSupportedAssetOrigin = AddAndEditSupportedAssetOrigin;
788
	type ResumeSupportedAssetOrigin = AddAndEditSupportedAssetOrigin;
789
	type RemoveSupportedAssetOrigin = RemoveSupportedAssetOrigin;
790
	type RuntimeEvent = RuntimeEvent;
791
	type WeightInfo = moonriver_weights::pallet_xcm_weight_trader::WeightInfo<Runtime>;
792
	type WeightToFee = <Runtime as pallet_transaction_payment::Config>::WeightToFee;
793
	type XcmFeesAccount = XcmFeesAccount;
794
	#[cfg(feature = "runtime-benchmarks")]
795
	type NotFilteredLocation = RelayLocation;
796
}
797

            
798
#[cfg(feature = "runtime-benchmarks")]
799
mod testing {
800
	use super::*;
801

            
802
	/// This From exists for benchmarking purposes. It has the potential side-effect of calling
803
	/// AssetManager::set_asset_type_asset_id() and should NOT be used in any production code.
804
	impl From<Location> for CurrencyId {
805
		fn from(location: Location) -> CurrencyId {
806
			use xcm_primitives::AssetTypeGetter;
807

            
808
			// If it does not exist, for benchmarking purposes, we create the association
809
			let asset_id = if let Some(asset_id) =
810
				AsAssetType::<AssetId, AssetType, AssetManager>::convert_location(&location)
811
			{
812
				asset_id
813
			} else {
814
				let asset_type: AssetType = location
815
					.try_into()
816
					.expect("Location convertion to AssetType should succeed");
817
				let asset_id: AssetId = asset_type.clone().into();
818
				AssetManager::set_asset_type_asset_id(asset_type, asset_id);
819
				asset_id
820
			};
821

            
822
			CurrencyId::ForeignAsset(asset_id)
823
		}
824
	}
825
}