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, EthereumLocation,
23
        EthereumNetwork, ForeignAssetsCreator, MaintenanceMode, MessageQueue, ParachainInfo,
24
        ParachainSystem, PolkadotXcm, Runtime, RuntimeBlockWeights, RuntimeCall, RuntimeEvent,
25
        RuntimeOrigin, TransactionByteFee, 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
    tp_xcm_commons::{EthereumAssetReserveForTanssi, EthereumAssetReserveFromParent},
57
    xcm::latest::prelude::*,
58
    xcm_builder::{
59
        AccountKey20Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
60
        AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ConvertedConcreteId,
61
        EnsureXcmOrigin, FungibleAdapter, IsConcrete, MintLocation, ParentIsPreset,
62
        RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
63
        SignedAccountKey20AsNative, SovereignSignedViaLocation, TakeWeightCredit, UsingComponents,
64
        WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents,
65
    },
66
    xcm_executor::XcmExecutor,
67
    xcm_primitives::AccountIdAssetIdConversion,
68
};
69

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

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

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

            
90
    pub const MaxAssetsIntoHolding: u32 = 64;
91

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

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

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

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

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

            
108
    /// Parent (relay/orchestrator chain) location for unpaid execution
109
    pub ParentLocation: Location = Location::parent();
110
}
111

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

            
117
pub type XcmBarrier = (
118
    // Weight that is paid for may be consumed.
119
    TakeWeightCredit,
120
    // Expected responses are OK.
121
    AllowKnownQueryResponses<PolkadotXcm>,
122
    // Allow unpaid execution from the parent chain (for LayerZero forwarded messages)
123
    AllowExplicitUnpaidExecutionFrom<Equals<ParentLocation>>,
124
    WithComputedOrigin<
125
        (
126
            // If the message is one that immediately attemps to pay for execution, then allow it.
127
            AllowTopLevelPaidExecutionFrom<Everything>,
128
            // Subscriptions for version tracking are OK.
129
            AllowSubscriptionsFrom<Everything>,
130
        ),
131
        UniversalLocation,
132
        ConstU32<8>,
133
    >,
134
);
135

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

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

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

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

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

            
198
/// Means for transacting assets on this chain.
199
pub type AssetTransactors = (CurrencyTransactor, ForeignFungiblesTransactor);
200
pub type XcmWeigher =
201
    WeightInfoBounds<XcmGenericWeights<RuntimeCall>, RuntimeCall, MaxInstructions>;
202

            
203
pub type UmpRouter =
204
    cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>;
205

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

            
222
pub struct XcmConfig;
223
impl xcm_executor::Config for XcmConfig {
224
    type RuntimeCall = RuntimeCall;
225
    type XcmSender = XcmRouter;
226
    type AssetTransactor = AssetTransactors;
227
    type OriginConverter = XcmOriginToTransactDispatchOrigin;
228
    // We admit as reserves:
229
    // - Native assets 'AllNative'
230
    // - Ethereum assets with ethereum or relay origin
231
    type IsReserve = (
232
        IsReserveFilter<Runtime>,
233
        EthereumAssetReserveForTanssi<EthereumLocation>,
234
        EthereumAssetReserveFromParent<EthereumLocation, EthereumNetwork>,
235
    );
236
    type IsTeleporter = IsTeleportFilter<Runtime>;
237
    type UniversalLocation = UniversalLocation;
238
    type Barrier = XcmBarrier;
239
    type Weigher = XcmWeigher;
240
    type Trader = (
241
        UsingComponents<WeightToFee, SelfReserve, AccountId, Balances, ()>,
242
        cumulus_primitives_utility::TakeFirstAssetTrader<
243
            AccountId,
244
            AssetRateAsMultiplier,
245
            // Use this currency when it is a fungible asset matching the given location or name:
246
            (ConvertedConcreteId<AssetId, Balance, ForeignAssetsCreator, JustTry>,),
247
            ForeignAssets,
248
            (),
249
        >,
250
    );
251
    type ResponseHandler = PolkadotXcm;
252
    type AssetTrap = PolkadotXcm;
253
    type AssetClaims = PolkadotXcm;
254
    type SubscriptionService = PolkadotXcm;
255
    type PalletInstancesInfo = AllPalletsWithSystem;
256
    type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
257
    type AssetLocker = ();
258
    type AssetExchanger = ();
259
    type FeeManager = XcmFeeManagerFromComponents<Equals<RootLocation>, ()>;
260
    type MessageExporter = ();
261
    type UniversalAliases = CommonUniversalAliases;
262
    type CallDispatcher = RuntimeCall;
263
    type SafeCallFilter = Everything;
264
    type Aliasers = Nothing;
265
    type TransactionalProcessor = xcm_builder::FrameTransactionalProcessor;
266
    type HrmpNewChannelOpenRequestHandler = ();
267
    type HrmpChannelAcceptedHandler = ();
268
    type HrmpChannelClosingHandler = ();
269
    type XcmRecorder = ();
270
    type XcmEventEmitter = PolkadotXcm;
271
}
272

            
273
impl pallet_xcm::Config for Runtime {
274
    type RuntimeEvent = RuntimeEvent;
275
    type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
276
    type XcmRouter = XcmRouter;
277
    type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
278
    type XcmExecuteFilter = Everything;
279
    type XcmExecutor = XcmExecutor<XcmConfig>;
280
    type XcmTeleportFilter = Nothing;
281
    type XcmReserveTransferFilter = Everything;
282
    type Weigher = XcmWeigher;
283
    type UniversalLocation = UniversalLocation;
284
    type RuntimeOrigin = RuntimeOrigin;
285
    type RuntimeCall = RuntimeCall;
286
    const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
287
    type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
288
    type Currency = Balances;
289
    type CurrencyMatcher = ();
290
    type TrustedLockers = ();
291
    type SovereignAccountOf = LocationToAccountId;
292
    type MaxLockers = ConstU32<8>;
293
    type MaxRemoteLockConsumers = ConstU32<0>;
294
    type RemoteLockConsumerIdentifier = ();
295
    type WeightInfo = weights::pallet_xcm::SubstrateWeight<Runtime>;
296
    type AdminOrigin = EnsureRoot<AccountId>;
297
    type AuthorizedAliasConsideration = Disabled;
298
}
299

            
300
pub type PriceForSiblingParachainDelivery =
301
    ExponentialPrice<SelfReserve, BaseDeliveryFee, TransactionByteFee, XcmpQueue>;
302

            
303
pub type PriceForParentDelivery =
304
    ExponentialPrice<SelfReserve, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
305

            
306
impl cumulus_pallet_xcmp_queue::Config for Runtime {
307
    type RuntimeEvent = RuntimeEvent;
308
    type ChannelInfo = ParachainSystem;
309
    type VersionWrapper = PolkadotXcm;
310
    type ControllerOrigin = EnsureRoot<AccountId>;
311
    type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
312
    type WeightInfo = weights::cumulus_pallet_xcmp_queue::SubstrateWeight<Runtime>;
313
    type PriceForSiblingDelivery = PriceForSiblingParachainDelivery;
314
    type XcmpQueue = TransformOrigin<MessageQueue, AggregateMessageOrigin, ParaId, ParaIdToSibling>;
315
    type MaxInboundSuspended = sp_core::ConstU32<1_000>;
316
    type MaxActiveOutboundChannels = ConstU32<128>;
317
    type MaxPageSize = ConstU32<{ 103 * 1024 }>;
318
}
319

            
320
impl cumulus_pallet_xcm::Config for Runtime {
321
    type RuntimeEvent = RuntimeEvent;
322
    type XcmExecutor = XcmExecutor<XcmConfig>;
323
}
324

            
325
parameter_types! {
326
    pub MessageQueueServiceWeight: Weight = Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block;
327
}
328

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

            
350
parameter_types! {
351
    // we just reuse the same deposits
352
    pub const ForeignAssetsAssetDeposit: Balance = 0;
353
    pub const ForeignAssetsAssetAccountDeposit: Balance = 0;
354
    pub const ForeignAssetsApprovalDeposit: Balance = 0;
355
    pub const ForeignAssetsAssetsStringLimit: u32 = 50;
356
    pub const ForeignAssetsMetadataDepositBase: Balance = 0;
357
    pub const ForeignAssetsMetadataDepositPerByte: Balance = 0;
358
    pub CheckingAccount: AccountId = PolkadotXcm::check_account();
359
    pub LocalCheckingAccount: (AccountId, MintLocation) = (CheckingAccount::get(), MintLocation::Local);
360
}
361

            
362
#[cfg(feature = "runtime-benchmarks")]
363
/// Simple conversion of `u32` into an `AssetId` for use in benchmarking.
364
pub struct ForeignAssetBenchmarkHelper;
365
#[cfg(feature = "runtime-benchmarks")]
366
impl pallet_assets::BenchmarkHelper<AssetId> for ForeignAssetBenchmarkHelper {
367
    fn create_asset_id_parameter(id: u32) -> AssetId {
368
        id.try_into()
369
            .expect("number too large to create benchmarks")
370
    }
371
}
372
#[cfg(feature = "runtime-benchmarks")]
373
impl pallet_asset_rate::AssetKindFactory<AssetId> for ForeignAssetBenchmarkHelper {
374
    fn create_asset_kind(id: u32) -> AssetId {
375
        id.try_into()
376
            .expect("number too large to create benchmarks")
377
    }
378
}
379

            
380
// Instruct how to go from an H160 to an AssetID
381
// We just take the lowest 2 bytes
382
impl AccountIdAssetIdConversion<AccountId, AssetId> for Runtime {
383
    /// The way to convert an account to assetId is by ensuring that the prefix is [0xFF, 18]
384
    /// and by taking the lowest 2 bytes as the assetId
385
    fn account_to_asset_id(account: AccountId) -> Option<(Vec<u8>, AssetId)> {
386
        let h160_account: H160 = account.into();
387
        let mut data = [0u8; 2];
388
        let (prefix_part, id_part) = h160_account.as_fixed_bytes().split_at(18);
389
        if prefix_part == FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX {
390
            data.copy_from_slice(id_part);
391
            let asset_id: AssetId = u16::from_be_bytes(data);
392
            Some((prefix_part.to_vec(), asset_id))
393
        } else {
394
            None
395
        }
396
    }
397

            
398
    // The opposite conversion
399
159
    fn asset_id_to_account(prefix: &[u8], asset_id: AssetId) -> AccountId {
400
159
        let mut data = [0u8; 20];
401
159
        data[0..18].copy_from_slice(prefix);
402
159
        data[18..20].copy_from_slice(&asset_id.to_be_bytes());
403
159
        AccountId::from(data)
404
159
    }
405
}
406

            
407
pub type AssetId = u16;
408
pub type ForeignAssetsInstance = pallet_assets::Instance1;
409
impl pallet_assets::Config<ForeignAssetsInstance> for Runtime {
410
    type RuntimeEvent = RuntimeEvent;
411
    type Balance = Balance;
412
    type AssetId = AssetId;
413
    type AssetIdParameter = AssetId;
414
    type Currency = Balances;
415
    type CreateOrigin = frame_support::traits::NeverEnsureOrigin<AccountId>;
416
    type ForceOrigin = EnsureRoot<AccountId>;
417
    type AssetDeposit = ForeignAssetsAssetDeposit;
418
    type MetadataDepositBase = ForeignAssetsMetadataDepositBase;
419
    type MetadataDepositPerByte = ForeignAssetsMetadataDepositPerByte;
420
    type ApprovalDeposit = ForeignAssetsApprovalDeposit;
421
    type StringLimit = ForeignAssetsAssetsStringLimit;
422
    type Freezer = ();
423
    type Extra = ();
424
    type WeightInfo = weights::pallet_assets::SubstrateWeight<Runtime>;
425
    type CallbackHandle = ();
426
    type AssetAccountDeposit = ForeignAssetsAssetAccountDeposit;
427
    type RemoveItemsLimit = frame_support::traits::ConstU32<1000>;
428
    type Holder = ();
429
    #[cfg(feature = "runtime-benchmarks")]
430
    type BenchmarkHelper = ForeignAssetBenchmarkHelper;
431
}
432

            
433
pub struct RevertCodePrecompileHook;
434

            
435
impl ForeignAssetCreatedHook<Location, AssetIdOf<Runtime>, AssetBalance<Runtime>>
436
    for RevertCodePrecompileHook
437
{
438
154
    fn on_asset_created(
439
154
        _foreign_asset: &Location,
440
154
        asset_id: &AssetIdOf<Runtime>,
441
154
        _min_balance: &AssetBalance<Runtime>,
442
154
    ) {
443
154
        let revert_bytecode = [0x60, 0x00, 0x60, 0x00, 0xFD].to_vec();
444
154
        let prefix_slice = [255u8; 18];
445
154
        let account_id = Runtime::asset_id_to_account(prefix_slice.as_slice(), *asset_id);
446

            
447
154
        let _ = pallet_evm::Pallet::<Runtime>::create_account(
448
154
            account_id.into(),
449
154
            revert_bytecode.clone(),
450
154
            None,
451
154
        );
452
154
    }
453
}
454

            
455
impl ForeignAssetDestroyedHook<Location, AssetIdOf<Runtime>> for RevertCodePrecompileHook {
456
    fn on_asset_destroyed(_foreign_asset: &Location, asset_id: &AssetIdOf<Runtime>) {
457
        let prefix_slice = [255u8; 18];
458
        let account_id = Runtime::asset_id_to_account(prefix_slice.as_slice(), *asset_id);
459

            
460
        pallet_evm::Pallet::<Runtime>::remove_account(&account_id.into());
461
    }
462
}
463

            
464
impl pallet_foreign_asset_creator::Config for Runtime {
465
    type ForeignAsset = Location;
466
    type ForeignAssetCreatorOrigin = EnsureRoot<AccountId>;
467
    type ForeignAssetModifierOrigin = EnsureRoot<AccountId>;
468
    type ForeignAssetDestroyerOrigin = EnsureRoot<AccountId>;
469
    type Fungibles = ForeignAssets;
470
    type WeightInfo = weights::pallet_foreign_asset_creator::SubstrateWeight<Runtime>;
471
    type OnForeignAssetCreated = RevertCodePrecompileHook;
472
    type OnForeignAssetDestroyed = RevertCodePrecompileHook;
473
}
474

            
475
impl pallet_asset_rate::Config for Runtime {
476
    type CreateOrigin = EnsureRoot<AccountId>;
477
    type RemoveOrigin = EnsureRoot<AccountId>;
478
    type UpdateOrigin = EnsureRoot<AccountId>;
479
    type Currency = Balances;
480
    type AssetKind = AssetId;
481
    type RuntimeEvent = RuntimeEvent;
482
    type WeightInfo = weights::pallet_asset_rate::SubstrateWeight<Runtime>;
483
    #[cfg(feature = "runtime-benchmarks")]
484
    type BenchmarkHelper = ForeignAssetBenchmarkHelper;
485
}
486

            
487
parameter_types! {
488
    pub const TrustPolicyMaxAssets: u32 = 10;
489
    pub const AllNativeTrustPolicy: DefaultTrustPolicy = DefaultTrustPolicy::AllNative;
490
    pub const AllNeverTrustPolicy: DefaultTrustPolicy = DefaultTrustPolicy::Never;
491
}
492
impl pallet_xcm_executor_utils::Config for Runtime {
493
    type TrustPolicyMaxAssets = TrustPolicyMaxAssets;
494
    type ReserveDefaultTrustPolicy = AllNativeTrustPolicy;
495
    type SetReserveTrustOrigin = EnsureRoot<AccountId>;
496
    type TeleportDefaultTrustPolicy = AllNeverTrustPolicy;
497
    type SetTeleportTrustOrigin = EnsureRoot<AccountId>;
498
    type WeightInfo = weights::pallet_xcm_executor_utils::SubstrateWeight<Runtime>;
499
}
500

            
501
use {
502
    crate::ForeignAssets,
503
    xcm_builder::{FungiblesAdapter, NoChecking},
504
    xcm_executor::traits::JustTry,
505
};
506

            
507
/// Means for transacting foreign assets from different global consensus.
508
pub type ForeignFungiblesTransactor = FungiblesAdapter<
509
    // Use this fungibles implementation:
510
    ForeignAssets,
511
    // Use this currency when it is a fungible asset matching the given location or name:
512
    (ConvertedConcreteId<AssetId, Balance, ForeignAssetsCreator, JustTry>,),
513
    // Convert an XCM Location into a local account id:
514
    LocationToAccountId,
515
    // Our chain's account ID type (we can't get away without mentioning it explicitly):
516
    AccountId,
517
    // We dont need to check teleports here.
518
    NoChecking,
519
    // The account to use for tracking teleports.
520
    CheckingAccount,
521
>;
522

            
523
/// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance.
524
pub type AssetRateAsMultiplier =
525
    AssetFeeAsExistentialDepositMultiplier<Runtime, WeightToFee, AssetRate, ForeignAssetsInstance>;
526

            
527
#[test]
528
1
fn test_asset_id_to_account_conversion() {
529
1
    let prefix_slice = [255u8].repeat(18);
530
1
    let asset_ids_to_check = vec![0u16, 123u16, 3453u16, 10000u16, 65535u16];
531
6
    for current_asset_id in asset_ids_to_check {
532
5
        let account_id = Runtime::asset_id_to_account(prefix_slice.as_slice(), current_asset_id);
533
5
        assert_eq!(
534
5
            account_id.to_string().to_lowercase(),
535
5
            String::from("0xffffffffffffffffffffffffffffffffffff")
536
5
                + format!("{:04x}", current_asset_id).as_str()
537
        );
538
    }
539
1
}