1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

            
4
// Tanssi 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
// Tanssi 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 Tanssi.  If not, see <http://www.gnu.org/licenses/>
16

            
17
use {
18
    super::{
19
        currency::MICROUNIT,
20
        precompiles::FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX,
21
        weights::{self, xcm::XcmWeight as XcmGenericWeights},
22
        AccountId, AllPalletsWithSystem, AssetRate, Balance, Balances, ForeignAssetsCreator,
23
        MaintenanceMode, MessageQueue, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime,
24
        RuntimeBlockWeights, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee,
25
        WeightToFee, XcmpQueue,
26
    },
27
    alloc::vec::Vec,
28
    ccp_xcm::SignedToAccountKey20,
29
    cumulus_primitives_core::{AggregateMessageOrigin, ParaId},
30
    frame_support::{
31
        parameter_types,
32
        traits::{Disabled, Equals, Everything, Get, Nothing, PalletInfoAccess, TransformOrigin},
33
        weights::Weight,
34
    },
35
    frame_system::EnsureRoot,
36
    pallet_foreign_asset_creator::{
37
        AssetBalance, AssetId as AssetIdOf, ForeignAssetCreatedHook, ForeignAssetDestroyedHook,
38
    },
39
    pallet_xcm::XcmPassthrough,
40
    pallet_xcm_executor_utils::{
41
        filters::{IsReserveFilter, IsTeleportFilter},
42
        DefaultTrustPolicy,
43
    },
44
    parachains_common::{
45
        message_queue::{NarrowOriginToSibling, ParaIdToSibling},
46
        xcm_config::AssetFeeAsExistentialDepositMultiplier,
47
    },
48
    polkadot_runtime_common::xcm_sender::ExponentialPrice,
49
    sp_core::{ConstU32, H160},
50
    sp_runtime::Perbill,
51
    tanssi_runtime_common::universal_aliases::CommonUniversalAliases,
52
    tp_container_chain::{
53
        sovereign_paid_remote_exporter::SovereignPaidRemoteExporter,
54
        ContainerChainEthereumLocationConverter,
55
    },
56
    xcm::latest::prelude::*,
57
    xcm_builder::{
58
        AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
59
        AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, EnsureXcmOrigin, FungibleAdapter,
60
        IsConcrete, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
61
        SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation,
62
        TakeWeightCredit, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
63
        XcmFeeManagerFromComponents,
64
    },
65
    xcm_executor::XcmExecutor,
66
    xcm_primitives::AccountIdAssetIdConversion,
67
};
68

            
69
parameter_types! {
70
    // Self Reserve location, defines the multilocation identifiying the self-reserve currency
71
    // This is used to match it also against our Balances pallet when we receive such
72
    // a Location: (Self Balances pallet index)
73
    // We use the RELATIVE multilocation
74
    pub SelfReserve: Location = Location {
75
        parents:0,
76
        interior: [
77
            PalletInstance(<Balances as PalletInfoAccess>::index() as u8)
78
        ].into()
79
    };
80

            
81
    // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate.
82
    pub UnitWeightCost: Weight = Weight::from_parts(1_000_000_000, 64 * 1024);
83
}
84

            
85
parameter_types! {
86
    // The relay chain Origin type
87
    pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
88

            
89
    pub const MaxAssetsIntoHolding: u32 = 64;
90

            
91
    /// Maximum number of instructions in a single XCM fragment. A sanity check against
92
    /// weight caculations getting too crazy.
93
    pub MaxInstructions: u32 = 100;
94

            
95
    // Dynamic RelayNetwork parameter - configurable via pallet_parameters
96
    pub RelayNetwork: NetworkId = crate::dynamic_params::xcm_config::RelayNetwork::get();
97

            
98
    // The universal location within the global consensus system
99
    pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into();
100

            
101
    pub const BaseDeliveryFee: u128 = 100 * MICROUNIT;
102
    pub RootLocation: Location = Location::here();
103

            
104
    // TODO: Revisit later
105
    pub const ContainerToEthTransferFee: u128 = 2_700_000_000_000u128;
106
}
107

            
108
#[cfg(feature = "runtime-benchmarks")]
109
parameter_types! {
110
    pub ReachableDest: Option<Location> = Some(Parent.into());
111
}
112

            
113
pub type XcmBarrier = (
114
    // Weight that is paid for may be consumed.
115
    TakeWeightCredit,
116
    // Expected responses are OK.
117
    AllowKnownQueryResponses<PolkadotXcm>,
118
    WithComputedOrigin<
119
        (
120
            // If the message is one that immediately attemps to pay for execution, then allow it.
121
            AllowTopLevelPaidExecutionFrom<Everything>,
122
            // Subscriptions for version tracking are OK.
123
            AllowSubscriptionsFrom<Everything>,
124
        ),
125
        UniversalLocation,
126
        ConstU32<8>,
127
    >,
128
);
129

            
130
// For benchmarking, we cannot use the describeFamily
131
// the benchmark is written to be able to convert an AccountId32, but describeFamily prevents this
132
#[cfg(not(feature = "runtime-benchmarks"))]
133
type Descriptor = xcm_builder::DescribeFamily<xcm_builder::DescribeAllTerminal>;
134
#[cfg(feature = "runtime-benchmarks")]
135
type Descriptor = xcm_builder::DescribeAllTerminal;
136

            
137
/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used
138
/// when determining ownership of accounts for asset transacting and when attempting to use XCM
139
/// `Transact` in order to determine the dispatch Origin.
140
pub type LocationToAccountId = (
141
    // The parent (Relay-chain) origin converts to the default `AccountId`.
142
    ParentIsPreset<AccountId>,
143
    // Sibling parachain origins convert to AccountId via the `ParaId::into`.
144
    SiblingParachainConvertsVia<polkadot_parachain_primitives::primitives::Sibling, AccountId>,
145
    // If we receive a Location of type AccountKey20, just generate a native account
146
    AccountKey20Aliases<RelayNetwork, AccountId>,
147
    // Generate remote accounts according to polkadot standards
148
    xcm_builder::HashedDescription<AccountId, Descriptor>,
149
    // Ethereum contract sovereign account.
150
    // (Used to convert ethereum contract locations to sovereign account)
151
    ContainerChainEthereumLocationConverter<AccountId>,
152
);
153

            
154
/// Local origins on this chain are allowed to dispatch XCM sends/executions.
155
pub type LocalOriginToLocation = SignedToAccountKey20<RuntimeOrigin, AccountId, RelayNetwork>;
156

            
157
/// Means for transacting the native currency on this chain.
158
pub type CurrencyTransactor = FungibleAdapter<
159
    // Use this currency:
160
    Balances,
161
    // Use this currency when it is a fungible asset matching the given location or name:
162
    IsConcrete<SelfReserve>,
163
    // Convert an XCM Location into a local account id:
164
    LocationToAccountId,
165
    // Our chain's account ID type (we can't get away without mentioning it explicitly):
166
    AccountId,
167
    // We don't track any teleports of `Balances`.
168
    (),
169
>;
170

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

            
192
/// Means for transacting assets on this chain.
193
pub type AssetTransactors = (CurrencyTransactor, ForeignFungiblesTransactor);
194
pub type XcmWeigher =
195
    WeightInfoBounds<XcmGenericWeights<RuntimeCall>, RuntimeCall, MaxInstructions>;
196

            
197
pub type UmpRouter =
198
    cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>;
199

            
200
/// The means for routing XCM messages which are not for local execution into the right message
201
/// queues.
202
pub type XcmRouter = WithUniqueTopic<(
203
    // Two routers - use UMP to communicate with the relay chain:
204
    UmpRouter,
205
    // ..and XCMP to communicate with the sibling chains.
206
    XcmpQueue,
207
    SovereignPaidRemoteExporter<
208
        UmpRouter,
209
        UniversalLocation,
210
        crate::EthereumNetwork,
211
        ContainerToEthTransferFee,
212
        ParachainInfo,
213
    >,
214
)>;
215

            
216
pub struct XcmConfig;
217
impl xcm_executor::Config for XcmConfig {
218
    type RuntimeCall = RuntimeCall;
219
    type XcmSender = XcmRouter;
220
    type AssetTransactor = AssetTransactors;
221
    type OriginConverter = XcmOriginToTransactDispatchOrigin;
222
    type IsReserve = IsReserveFilter<Runtime>;
223
    type IsTeleporter = IsTeleportFilter<Runtime>;
224
    type UniversalLocation = UniversalLocation;
225
    type Barrier = XcmBarrier;
226
    type Weigher = XcmWeigher;
227
    type Trader = (
228
        UsingComponents<WeightToFee, SelfReserve, AccountId, Balances, ()>,
229
        cumulus_primitives_utility::TakeFirstAssetTrader<
230
            AccountId,
231
            AssetRateAsMultiplier,
232
            // Use this currency when it is a fungible asset matching the given location or name:
233
            (ConvertedConcreteId<AssetId, Balance, ForeignAssetsCreator, JustTry>,),
234
            ForeignAssets,
235
            (),
236
        >,
237
    );
238
    type ResponseHandler = PolkadotXcm;
239
    type AssetTrap = PolkadotXcm;
240
    type AssetClaims = PolkadotXcm;
241
    type SubscriptionService = PolkadotXcm;
242
    type PalletInstancesInfo = AllPalletsWithSystem;
243
    type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
244
    type AssetLocker = ();
245
    type AssetExchanger = ();
246
    type FeeManager = XcmFeeManagerFromComponents<Equals<RootLocation>, ()>;
247
    type MessageExporter = ();
248
    type UniversalAliases = CommonUniversalAliases;
249
    type CallDispatcher = RuntimeCall;
250
    type SafeCallFilter = Everything;
251
    type Aliasers = Nothing;
252
    type TransactionalProcessor = xcm_builder::FrameTransactionalProcessor;
253
    type HrmpNewChannelOpenRequestHandler = ();
254
    type HrmpChannelAcceptedHandler = ();
255
    type HrmpChannelClosingHandler = ();
256
    type XcmRecorder = ();
257
    type XcmEventEmitter = PolkadotXcm;
258
}
259

            
260
impl pallet_xcm::Config for Runtime {
261
    type RuntimeEvent = RuntimeEvent;
262
    type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
263
    type XcmRouter = XcmRouter;
264
    type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
265
    type XcmExecuteFilter = Everything;
266
    type XcmExecutor = XcmExecutor<XcmConfig>;
267
    type XcmTeleportFilter = Nothing;
268
    type XcmReserveTransferFilter = Everything;
269
    type Weigher = XcmWeigher;
270
    type UniversalLocation = UniversalLocation;
271
    type RuntimeOrigin = RuntimeOrigin;
272
    type RuntimeCall = RuntimeCall;
273
    const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
274
    type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
275
    type Currency = Balances;
276
    type CurrencyMatcher = ();
277
    type TrustedLockers = ();
278
    type SovereignAccountOf = LocationToAccountId;
279
    type MaxLockers = ConstU32<8>;
280
    type MaxRemoteLockConsumers = ConstU32<0>;
281
    type RemoteLockConsumerIdentifier = ();
282
    type WeightInfo = weights::pallet_xcm::SubstrateWeight<Runtime>;
283
    type AdminOrigin = EnsureRoot<AccountId>;
284
    type AuthorizedAliasConsideration = Disabled;
285
}
286

            
287
pub type PriceForSiblingParachainDelivery =
288
    ExponentialPrice<SelfReserve, BaseDeliveryFee, TransactionByteFee, XcmpQueue>;
289

            
290
pub type PriceForParentDelivery =
291
    ExponentialPrice<SelfReserve, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
292

            
293
impl cumulus_pallet_xcmp_queue::Config for Runtime {
294
    type RuntimeEvent = RuntimeEvent;
295
    type ChannelInfo = ParachainSystem;
296
    type VersionWrapper = PolkadotXcm;
297
    type ControllerOrigin = EnsureRoot<AccountId>;
298
    type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
299
    type WeightInfo = weights::cumulus_pallet_xcmp_queue::SubstrateWeight<Runtime>;
300
    type PriceForSiblingDelivery = PriceForSiblingParachainDelivery;
301
    type XcmpQueue = TransformOrigin<MessageQueue, AggregateMessageOrigin, ParaId, ParaIdToSibling>;
302
    type MaxInboundSuspended = sp_core::ConstU32<1_000>;
303
    type MaxActiveOutboundChannels = ConstU32<128>;
304
    type MaxPageSize = ConstU32<{ 103 * 1024 }>;
305
}
306

            
307
impl cumulus_pallet_xcm::Config for Runtime {
308
    type RuntimeEvent = RuntimeEvent;
309
    type XcmExecutor = XcmExecutor<XcmConfig>;
310
}
311

            
312
parameter_types! {
313
    pub MessageQueueServiceWeight: Weight = Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block;
314
}
315

            
316
impl pallet_message_queue::Config for Runtime {
317
    type RuntimeEvent = RuntimeEvent;
318
    type WeightInfo = weights::pallet_message_queue::SubstrateWeight<Self>;
319
    #[cfg(feature = "runtime-benchmarks")]
320
    type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor<
321
        cumulus_primitives_core::AggregateMessageOrigin,
322
    >;
323
    #[cfg(not(feature = "runtime-benchmarks"))]
324
    type MessageProcessor =
325
        xcm_builder::ProcessXcmMessage<AggregateMessageOrigin, XcmExecutor<XcmConfig>, RuntimeCall>;
326
    type Size = u32;
327
    // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin:
328
    type QueueChangeHandler = NarrowOriginToSibling<XcmpQueue>;
329
    // NarrowOriginToSibling calls XcmpQueue's is_pause if Origin is sibling. Allows all other origins
330
    type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling<XcmpQueue>);
331
    type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
332
    type MaxStale = sp_core::ConstU32<8>;
333
    type ServiceWeight = MessageQueueServiceWeight;
334
    type IdleMaxServiceWeight = MessageQueueServiceWeight;
335
}
336

            
337
parameter_types! {
338
    // we just reuse the same deposits
339
    pub const ForeignAssetsAssetDeposit: Balance = 0;
340
    pub const ForeignAssetsAssetAccountDeposit: Balance = 0;
341
    pub const ForeignAssetsApprovalDeposit: Balance = 0;
342
    pub const ForeignAssetsAssetsStringLimit: u32 = 50;
343
    pub const ForeignAssetsMetadataDepositBase: Balance = 0;
344
    pub const ForeignAssetsMetadataDepositPerByte: Balance = 0;
345
    pub CheckingAccount: AccountId = PolkadotXcm::check_account();
346
}
347

            
348
#[cfg(feature = "runtime-benchmarks")]
349
/// Simple conversion of `u32` into an `AssetId` for use in benchmarking.
350
pub struct ForeignAssetBenchmarkHelper;
351
#[cfg(feature = "runtime-benchmarks")]
352
impl pallet_assets::BenchmarkHelper<AssetId> for ForeignAssetBenchmarkHelper {
353
    fn create_asset_id_parameter(id: u32) -> AssetId {
354
        id.try_into()
355
            .expect("number too large to create benchmarks")
356
    }
357
}
358
#[cfg(feature = "runtime-benchmarks")]
359
impl pallet_asset_rate::AssetKindFactory<AssetId> for ForeignAssetBenchmarkHelper {
360
    fn create_asset_kind(id: u32) -> AssetId {
361
        id.try_into()
362
            .expect("number too large to create benchmarks")
363
    }
364
}
365

            
366
// Instruct how to go from an H160 to an AssetID
367
// We just take the lowest 2 bytes
368
impl AccountIdAssetIdConversion<AccountId, AssetId> for Runtime {
369
    /// The way to convert an account to assetId is by ensuring that the prefix is [0xFF, 18]
370
    /// and by taking the lowest 2 bytes as the assetId
371
    fn account_to_asset_id(account: AccountId) -> Option<(Vec<u8>, AssetId)> {
372
        let h160_account: H160 = account.into();
373
        let mut data = [0u8; 2];
374
        let (prefix_part, id_part) = h160_account.as_fixed_bytes().split_at(18);
375
        if prefix_part == FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX {
376
            data.copy_from_slice(id_part);
377
            let asset_id: AssetId = u16::from_be_bytes(data);
378
            Some((prefix_part.to_vec(), asset_id))
379
        } else {
380
            None
381
        }
382
    }
383

            
384
    // The opposite conversion
385
38
    fn asset_id_to_account(prefix: &[u8], asset_id: AssetId) -> AccountId {
386
38
        let mut data = [0u8; 20];
387
38
        data[0..18].copy_from_slice(prefix);
388
38
        data[18..20].copy_from_slice(&asset_id.to_be_bytes());
389
38
        AccountId::from(data)
390
38
    }
391
}
392

            
393
pub type AssetId = u16;
394
pub type ForeignAssetsInstance = pallet_assets::Instance1;
395
impl pallet_assets::Config<ForeignAssetsInstance> for Runtime {
396
    type RuntimeEvent = RuntimeEvent;
397
    type Balance = Balance;
398
    type AssetId = AssetId;
399
    type AssetIdParameter = AssetId;
400
    type Currency = Balances;
401
    type CreateOrigin = frame_support::traits::NeverEnsureOrigin<AccountId>;
402
    type ForceOrigin = EnsureRoot<AccountId>;
403
    type AssetDeposit = ForeignAssetsAssetDeposit;
404
    type MetadataDepositBase = ForeignAssetsMetadataDepositBase;
405
    type MetadataDepositPerByte = ForeignAssetsMetadataDepositPerByte;
406
    type ApprovalDeposit = ForeignAssetsApprovalDeposit;
407
    type StringLimit = ForeignAssetsAssetsStringLimit;
408
    type Freezer = ();
409
    type Extra = ();
410
    type WeightInfo = weights::pallet_assets::SubstrateWeight<Runtime>;
411
    type CallbackHandle = ();
412
    type AssetAccountDeposit = ForeignAssetsAssetAccountDeposit;
413
    type RemoveItemsLimit = frame_support::traits::ConstU32<1000>;
414
    type Holder = ();
415
    #[cfg(feature = "runtime-benchmarks")]
416
    type BenchmarkHelper = ForeignAssetBenchmarkHelper;
417
}
418

            
419
pub struct RevertCodePrecompileHook;
420

            
421
impl ForeignAssetCreatedHook<Location, AssetIdOf<Runtime>, AssetBalance<Runtime>>
422
    for RevertCodePrecompileHook
423
{
424
33
    fn on_asset_created(
425
33
        _foreign_asset: &Location,
426
33
        asset_id: &AssetIdOf<Runtime>,
427
33
        _min_balance: &AssetBalance<Runtime>,
428
33
    ) {
429
33
        let revert_bytecode = [0x60, 0x00, 0x60, 0x00, 0xFD].to_vec();
430
33
        let prefix_slice = [255u8; 18];
431
33
        let account_id = Runtime::asset_id_to_account(prefix_slice.as_slice(), *asset_id);
432
33

            
433
33
        let _ = pallet_evm::Pallet::<Runtime>::create_account(
434
33
            account_id.into(),
435
33
            revert_bytecode.clone(),
436
33
            None,
437
33
        );
438
33
    }
439
}
440

            
441
impl ForeignAssetDestroyedHook<Location, AssetIdOf<Runtime>> for RevertCodePrecompileHook {
442
    fn on_asset_destroyed(_foreign_asset: &Location, asset_id: &AssetIdOf<Runtime>) {
443
        let prefix_slice = [255u8; 18];
444
        let account_id = Runtime::asset_id_to_account(prefix_slice.as_slice(), *asset_id);
445

            
446
        pallet_evm::Pallet::<Runtime>::remove_account(&account_id.into());
447
    }
448
}
449

            
450
impl pallet_foreign_asset_creator::Config for Runtime {
451
    type RuntimeEvent = RuntimeEvent;
452
    type ForeignAsset = Location;
453
    type ForeignAssetCreatorOrigin = EnsureRoot<AccountId>;
454
    type ForeignAssetModifierOrigin = EnsureRoot<AccountId>;
455
    type ForeignAssetDestroyerOrigin = EnsureRoot<AccountId>;
456
    type Fungibles = ForeignAssets;
457
    type WeightInfo = weights::pallet_foreign_asset_creator::SubstrateWeight<Runtime>;
458
    type OnForeignAssetCreated = RevertCodePrecompileHook;
459
    type OnForeignAssetDestroyed = RevertCodePrecompileHook;
460
}
461

            
462
impl pallet_asset_rate::Config for Runtime {
463
    type CreateOrigin = EnsureRoot<AccountId>;
464
    type RemoveOrigin = EnsureRoot<AccountId>;
465
    type UpdateOrigin = EnsureRoot<AccountId>;
466
    type Currency = Balances;
467
    type AssetKind = AssetId;
468
    type RuntimeEvent = RuntimeEvent;
469
    type WeightInfo = weights::pallet_asset_rate::SubstrateWeight<Runtime>;
470
    #[cfg(feature = "runtime-benchmarks")]
471
    type BenchmarkHelper = ForeignAssetBenchmarkHelper;
472
}
473

            
474
parameter_types! {
475
    pub const TrustPolicyMaxAssets: u32 = 10;
476
    pub const AllNativeTrustPolicy: DefaultTrustPolicy = DefaultTrustPolicy::AllNative;
477
    pub const AllNeverTrustPolicy: DefaultTrustPolicy = DefaultTrustPolicy::Never;
478
}
479
impl pallet_xcm_executor_utils::Config for Runtime {
480
    type RuntimeEvent = RuntimeEvent;
481
    type TrustPolicyMaxAssets = TrustPolicyMaxAssets;
482
    type ReserveDefaultTrustPolicy = AllNativeTrustPolicy;
483
    type SetReserveTrustOrigin = EnsureRoot<AccountId>;
484
    type TeleportDefaultTrustPolicy = AllNeverTrustPolicy;
485
    type SetTeleportTrustOrigin = EnsureRoot<AccountId>;
486
    type WeightInfo = weights::pallet_xcm_executor_utils::SubstrateWeight<Runtime>;
487
}
488

            
489
use {
490
    crate::ForeignAssets,
491
    xcm_builder::{FungiblesAdapter, NoChecking},
492
    xcm_executor::traits::JustTry,
493
};
494

            
495
/// Means for transacting foreign assets from different global consensus.
496
pub type ForeignFungiblesTransactor = FungiblesAdapter<
497
    // Use this fungibles implementation:
498
    ForeignAssets,
499
    // Use this currency when it is a fungible asset matching the given location or name:
500
    (ConvertedConcreteId<AssetId, Balance, ForeignAssetsCreator, JustTry>,),
501
    // Convert an XCM Location into a local account id:
502
    LocationToAccountId,
503
    // Our chain's account ID type (we can't get away without mentioning it explicitly):
504
    AccountId,
505
    // We dont need to check teleports here.
506
    NoChecking,
507
    // The account to use for tracking teleports.
508
    CheckingAccount,
509
>;
510

            
511
/// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance.
512
pub type AssetRateAsMultiplier =
513
    AssetFeeAsExistentialDepositMultiplier<Runtime, WeightToFee, AssetRate, ForeignAssetsInstance>;
514

            
515
#[test]
516
1
fn test_asset_id_to_account_conversion() {
517
1
    let prefix_slice = [255u8].repeat(18);
518
1
    let asset_ids_to_check = vec![0u16, 123u16, 3453u16, 10000u16, 65535u16];
519
6
    for current_asset_id in asset_ids_to_check {
520
5
        let account_id = Runtime::asset_id_to_account(prefix_slice.as_slice(), current_asset_id);
521
5
        assert_eq!(
522
5
            account_id.to_string().to_lowercase(),
523
5
            String::from("0xffffffffffffffffffffffffffffffffffff")
524
5
                + format!("{:04x}", current_asset_id).as_str()
525
5
        );
526
    }
527
1
}