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
    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
pub const DANCELIGHT_GENESIS_HASH: [u8; 32] =
70
    hex_literal::hex!["983a1a72503d6cc3636776747ec627172b51272bf45e50a355348facb67a820a"];
71

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

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

            
87
    // For now this is being unused for our use cases (e.g container token transfers).
88
    // We might need to revisit this later and make it dynamic (through pallet params for instance).
89
    pub const RelayNetwork: NetworkId = NetworkId::ByGenesis(DANCELIGHT_GENESIS_HASH);
90

            
91
    // The relay chain Origin type
92
    pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
93

            
94
    pub const MaxAssetsIntoHolding: u32 = 64;
95

            
96
    /// Maximum number of instructions in a single XCM fragment. A sanity check against
97
    /// weight caculations getting too crazy.
98
    pub MaxInstructions: u32 = 100;
99

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

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

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

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

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

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

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

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

            
159
/// Means for transacting the native currency on this chain.
160
pub type CurrencyTransactor = FungibleAdapter<
161
    // Use this currency:
162
    Balances,
163
    // Use this currency when it is a fungible asset matching the given location or name:
164
    IsConcrete<SelfReserve>,
165
    // Convert an XCM Location into a local account id:
166
    LocationToAccountId,
167
    // Our chain's account ID type (we can't get away without mentioning it explicitly):
168
    AccountId,
169
    // We don't track any teleports of `Balances`.
170
    (),
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 convert 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
    // Native signed account converter; this just converts an `AccountId32` origin into a normal
188
    // `RuntimeOrigin::Signed` origin of the same 32-byte value.
189
    SignedAccountKey20AsNative<RelayNetwork, RuntimeOrigin>,
190
    // Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
191
    XcmPassthrough<RuntimeOrigin>,
192
);
193

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

            
199
pub type UmpRouter =
200
    cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>;
201

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
420
pub struct RevertCodePrecompileHook;
421

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

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

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

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

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

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

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

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

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

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

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