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, 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
    tp_container_chain::{
52
        sovereign_paid_remote_exporter::SovereignPaidRemoteExporter,
53
        ContainerChainEthereumLocationConverter,
54
    },
55
    xcm::latest::prelude::*,
56
    xcm_builder::{
57
        AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
58
        AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, EnsureXcmOrigin, FungibleAdapter,
59
        IsConcrete, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
60
        SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation,
61
        TakeWeightCredit, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
62
        XcmFeeManagerFromComponents,
63
    },
64
    xcm_executor::XcmExecutor,
65
    xcm_primitives::AccountIdAssetIdConversion,
66
};
67
parameter_types! {
68
    // Self Reserve location, defines the multilocation identifiying the self-reserve currency
69
    // This is used to match it also against our Balances pallet when we receive such
70
    // a Location: (Self Balances pallet index)
71
    // We use the RELATIVE multilocation
72
    pub SelfReserve: Location = Location {
73
        parents:0,
74
        interior: [
75
            PalletInstance(<Balances as PalletInfoAccess>::index() as u8)
76
        ].into()
77
    };
78

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

            
82
    // TODO: revisit
83
    pub const RelayNetwork: NetworkId = NetworkId::Polkadot;
84

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

            
88
    pub const MaxAssetsIntoHolding: u32 = 64;
89

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

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

            
97
    pub const BaseDeliveryFee: u128 = 100 * MICROUNIT;
98
    pub RootLocation: Location = Location::here();
99

            
100
    // TODO: Revisit later
101
    pub const ContainerToEthTransferFee: u128 = 2_700_000_000_000u128;
102
}
103

            
104
#[cfg(feature = "runtime-benchmarks")]
105
parameter_types! {
106
    pub ReachableDest: Option<Location> = Some(Parent.into());
107
}
108

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

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

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

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

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

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

            
188
/// Means for transacting assets on this chain.
189
pub type AssetTransactors = (CurrencyTransactor, ForeignFungiblesTransactor);
190
pub type XcmWeigher =
191
    WeightInfoBounds<XcmGenericWeights<RuntimeCall>, RuntimeCall, MaxInstructions>;
192

            
193
pub type UmpRouter =
194
    cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>;
195

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

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

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

            
282
pub type PriceForSiblingParachainDelivery =
283
    ExponentialPrice<SelfReserve, BaseDeliveryFee, TransactionByteFee, XcmpQueue>;
284

            
285
pub type PriceForParentDelivery =
286
    ExponentialPrice<SelfReserve, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
287

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

            
302
impl cumulus_pallet_xcm::Config for Runtime {
303
    type RuntimeEvent = RuntimeEvent;
304
    type XcmExecutor = XcmExecutor<XcmConfig>;
305
}
306

            
307
parameter_types! {
308
    pub MessageQueueServiceWeight: Weight = Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block;
309
}
310

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

            
332
parameter_types! {
333
    // we just reuse the same deposits
334
    pub const ForeignAssetsAssetDeposit: Balance = 0;
335
    pub const ForeignAssetsAssetAccountDeposit: Balance = 0;
336
    pub const ForeignAssetsApprovalDeposit: Balance = 0;
337
    pub const ForeignAssetsAssetsStringLimit: u32 = 50;
338
    pub const ForeignAssetsMetadataDepositBase: Balance = 0;
339
    pub const ForeignAssetsMetadataDepositPerByte: Balance = 0;
340
    pub CheckingAccount: AccountId = PolkadotXcm::check_account();
341
}
342

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

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

            
379
    // The opposite conversion
380
38
    fn asset_id_to_account(prefix: &[u8], asset_id: AssetId) -> AccountId {
381
38
        let mut data = [0u8; 20];
382
38
        data[0..18].copy_from_slice(prefix);
383
38
        data[18..20].copy_from_slice(&asset_id.to_be_bytes());
384
38
        AccountId::from(data)
385
38
    }
386
}
387

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

            
414
pub struct RevertCodePrecompileHook;
415

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

            
428
33
        let _ = pallet_evm::Pallet::<Runtime>::create_account(
429
33
            account_id.into(),
430
33
            revert_bytecode.clone(),
431
33
            None,
432
33
        );
433
33
    }
434
}
435

            
436
impl ForeignAssetDestroyedHook<Location, AssetIdOf<Runtime>> for RevertCodePrecompileHook {
437
    fn on_asset_destroyed(_foreign_asset: &Location, asset_id: &AssetIdOf<Runtime>) {
438
        let prefix_slice = [255u8; 18];
439
        let account_id = Runtime::asset_id_to_account(prefix_slice.as_slice(), *asset_id);
440

            
441
        pallet_evm::Pallet::<Runtime>::remove_account(&account_id.into());
442
    }
443
}
444

            
445
impl pallet_foreign_asset_creator::Config for Runtime {
446
    type RuntimeEvent = RuntimeEvent;
447
    type ForeignAsset = Location;
448
    type ForeignAssetCreatorOrigin = EnsureRoot<AccountId>;
449
    type ForeignAssetModifierOrigin = EnsureRoot<AccountId>;
450
    type ForeignAssetDestroyerOrigin = EnsureRoot<AccountId>;
451
    type Fungibles = ForeignAssets;
452
    type WeightInfo = weights::pallet_foreign_asset_creator::SubstrateWeight<Runtime>;
453
    type OnForeignAssetCreated = RevertCodePrecompileHook;
454
    type OnForeignAssetDestroyed = RevertCodePrecompileHook;
455
}
456

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

            
469
parameter_types! {
470
    pub const TrustPolicyMaxAssets: u32 = 1000;
471
    pub const AllNativeTrustPolicy: DefaultTrustPolicy = DefaultTrustPolicy::AllNative;
472
    pub const AllNeverTrustPolicy: DefaultTrustPolicy = DefaultTrustPolicy::Never;
473
}
474
impl pallet_xcm_executor_utils::Config for Runtime {
475
    type RuntimeEvent = RuntimeEvent;
476
    type TrustPolicyMaxAssets = TrustPolicyMaxAssets;
477
    type ReserveDefaultTrustPolicy = AllNativeTrustPolicy;
478
    type SetReserveTrustOrigin = EnsureRoot<AccountId>;
479
    type TeleportDefaultTrustPolicy = AllNeverTrustPolicy;
480
    type SetTeleportTrustOrigin = EnsureRoot<AccountId>;
481
    type WeightInfo = weights::pallet_xcm_executor_utils::SubstrateWeight<Runtime>;
482
}
483

            
484
use {
485
    crate::ForeignAssets,
486
    xcm_builder::{FungiblesAdapter, NoChecking},
487
    xcm_executor::traits::JustTry,
488
};
489

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

            
506
/// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance.
507
pub type AssetRateAsMultiplier =
508
    AssetFeeAsExistentialDepositMultiplier<Runtime, WeightToFee, AssetRate, ForeignAssetsInstance>;
509

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