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
    ccp_xcm::SignedToAccountKey20,
28
    cumulus_primitives_core::{AggregateMessageOrigin, ParaId},
29
    frame_support::{
30
        parameter_types,
31
        traits::{Disabled, Equals, Everything, Nothing, PalletInfoAccess, TransformOrigin},
32
        weights::Weight,
33
    },
34
    frame_system::EnsureRoot,
35
    pallet_foreign_asset_creator::{
36
        AssetBalance, AssetId as AssetIdOf, ForeignAssetCreatedHook, ForeignAssetDestroyedHook,
37
    },
38
    pallet_xcm::XcmPassthrough,
39
    pallet_xcm_executor_utils::{
40
        filters::{IsReserveFilter, IsTeleportFilter},
41
        DefaultTrustPolicy,
42
    },
43
    parachains_common::{
44
        message_queue::{NarrowOriginToSibling, ParaIdToSibling},
45
        xcm_config::AssetFeeAsExistentialDepositMultiplier,
46
    },
47
    polkadot_runtime_common::xcm_sender::ExponentialPrice,
48
    sp_core::{ConstU32, H160},
49
    sp_runtime::Perbill,
50
    sp_std::vec::Vec,
51
    xcm::latest::prelude::*,
52
    xcm_builder::{
53
        AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
54
        AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, EnsureXcmOrigin, FungibleAdapter,
55
        IsConcrete, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
56
        SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation,
57
        TakeWeightCredit, UsingComponents, WeightInfoBounds, WithComputedOrigin,
58
        XcmFeeManagerFromComponents,
59
    },
60
    xcm_executor::XcmExecutor,
61
    xcm_primitives::AccountIdAssetIdConversion,
62
};
63
parameter_types! {
64
    // Self Reserve location, defines the multilocation identifiying the self-reserve currency
65
    // This is used to match it also against our Balances pallet when we receive such
66
    // a Location: (Self Balances pallet index)
67
    // We use the RELATIVE multilocation
68
    pub SelfReserve: Location = Location {
69
        parents:0,
70
        interior: [
71
            PalletInstance(<Balances as PalletInfoAccess>::index() as u8)
72
        ].into()
73
    };
74

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

            
78
    // TODO: revisit
79
    pub const RelayNetwork: NetworkId = NetworkId::Polkadot;
80

            
81
    // The relay chain Origin type
82
    pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
83

            
84
    pub const MaxAssetsIntoHolding: u32 = 64;
85

            
86
    /// Maximum number of instructions in a single XCM fragment. A sanity check against
87
    /// weight caculations getting too crazy.
88
    pub MaxInstructions: u32 = 100;
89

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

            
93
    pub const BaseDeliveryFee: u128 = 100 * MICROUNIT;
94
    pub RootLocation: Location = Location::here();
95
}
96

            
97
#[cfg(feature = "runtime-benchmarks")]
98
parameter_types! {
99
    pub ReachableDest: Option<Location> = Some(Parent.into());
100
}
101

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

            
119
// For benchmarking, we cannot use the describeFamily
120
// the benchmark is written to be able to convert an AccountId32, but describeFamily prevents this
121
#[cfg(not(feature = "runtime-benchmarks"))]
122
type Descriptor = xcm_builder::DescribeFamily<xcm_builder::DescribeAllTerminal>;
123
#[cfg(feature = "runtime-benchmarks")]
124
type Descriptor = xcm_builder::DescribeAllTerminal;
125

            
126
/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used
127
/// when determining ownership of accounts for asset transacting and when attempting to use XCM
128
/// `Transact` in order to determine the dispatch Origin.
129
pub type LocationToAccountId = (
130
    // The parent (Relay-chain) origin converts to the default `AccountId`.
131
    ParentIsPreset<AccountId>,
132
    // Sibling parachain origins convert to AccountId via the `ParaId::into`.
133
    SiblingParachainConvertsVia<polkadot_parachain_primitives::primitives::Sibling, AccountId>,
134
    // If we receive a Location of type AccountKey20, just generate a native account
135
    AccountKey20Aliases<RelayNetwork, AccountId>,
136
    // Generate remote accounts according to polkadot standards
137
    xcm_builder::HashedDescription<AccountId, Descriptor>,
138
);
139

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

            
143
/// Means for transacting the native currency on this chain.
144
pub type CurrencyTransactor = FungibleAdapter<
145
    // Use this currency:
146
    Balances,
147
    // Use this currency when it is a fungible asset matching the given location or name:
148
    IsConcrete<SelfReserve>,
149
    // Convert an XCM Location into a local account id:
150
    LocationToAccountId,
151
    // Our chain's account ID type (we can't get away without mentioning it explicitly):
152
    AccountId,
153
    // We don't track any teleports of `Balances`.
154
    (),
155
>;
156

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

            
178
/// Means for transacting assets on this chain.
179
pub type AssetTransactors = (CurrencyTransactor, ForeignFungiblesTransactor);
180
pub type XcmWeigher =
181
    WeightInfoBounds<XcmGenericWeights<RuntimeCall>, RuntimeCall, MaxInstructions>;
182

            
183
/// The means for routing XCM messages which are not for local execution into the right message
184
/// queues.
185
pub type XcmRouter = (
186
    // Two routers - use UMP to communicate with the relay chain:
187
    cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>,
188
    // ..and XCMP to communicate with the sibling chains.
189
    XcmpQueue,
190
);
191

            
192
pub struct XcmConfig;
193
impl xcm_executor::Config for XcmConfig {
194
    type RuntimeCall = RuntimeCall;
195
    type XcmSender = XcmRouter;
196
    type AssetTransactor = AssetTransactors;
197
    type OriginConverter = XcmOriginToTransactDispatchOrigin;
198
    type IsReserve = IsReserveFilter<Runtime>;
199
    type IsTeleporter = IsTeleportFilter<Runtime>;
200
    type UniversalLocation = UniversalLocation;
201
    type Barrier = XcmBarrier;
202
    type Weigher = XcmWeigher;
203
    type Trader = (
204
        UsingComponents<WeightToFee, SelfReserve, AccountId, Balances, ()>,
205
        cumulus_primitives_utility::TakeFirstAssetTrader<
206
            AccountId,
207
            AssetRateAsMultiplier,
208
            // Use this currency when it is a fungible asset matching the given location or name:
209
            (ConvertedConcreteId<AssetId, Balance, ForeignAssetsCreator, JustTry>,),
210
            ForeignAssets,
211
            (),
212
        >,
213
    );
214
    type ResponseHandler = PolkadotXcm;
215
    type AssetTrap = PolkadotXcm;
216
    type AssetClaims = PolkadotXcm;
217
    type SubscriptionService = PolkadotXcm;
218
    type PalletInstancesInfo = AllPalletsWithSystem;
219
    type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
220
    type AssetLocker = ();
221
    type AssetExchanger = ();
222
    type FeeManager = XcmFeeManagerFromComponents<Equals<RootLocation>, ()>;
223
    type MessageExporter = ();
224
    type UniversalAliases = Nothing;
225
    type CallDispatcher = RuntimeCall;
226
    type SafeCallFilter = Everything;
227
    type Aliasers = Nothing;
228
    type TransactionalProcessor = xcm_builder::FrameTransactionalProcessor;
229
    type HrmpNewChannelOpenRequestHandler = ();
230
    type HrmpChannelAcceptedHandler = ();
231
    type HrmpChannelClosingHandler = ();
232
    type XcmRecorder = ();
233
    type XcmEventEmitter = PolkadotXcm;
234
}
235

            
236
impl pallet_xcm::Config for Runtime {
237
    type RuntimeEvent = RuntimeEvent;
238
    type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
239
    type XcmRouter = XcmRouter;
240
    type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
241
    type XcmExecuteFilter = Everything;
242
    type XcmExecutor = XcmExecutor<XcmConfig>;
243
    type XcmTeleportFilter = Nothing;
244
    type XcmReserveTransferFilter = Everything;
245
    type Weigher = XcmWeigher;
246
    type UniversalLocation = UniversalLocation;
247
    type RuntimeOrigin = RuntimeOrigin;
248
    type RuntimeCall = RuntimeCall;
249
    const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
250
    type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
251
    type Currency = Balances;
252
    type CurrencyMatcher = ();
253
    type TrustedLockers = ();
254
    type SovereignAccountOf = LocationToAccountId;
255
    type MaxLockers = ConstU32<8>;
256
    type MaxRemoteLockConsumers = ConstU32<0>;
257
    type RemoteLockConsumerIdentifier = ();
258
    type WeightInfo = weights::pallet_xcm::SubstrateWeight<Runtime>;
259
    type AdminOrigin = EnsureRoot<AccountId>;
260
    type AuthorizedAliasConsideration = Disabled;
261
}
262

            
263
pub type PriceForSiblingParachainDelivery =
264
    ExponentialPrice<SelfReserve, BaseDeliveryFee, TransactionByteFee, XcmpQueue>;
265

            
266
pub type PriceForParentDelivery =
267
    ExponentialPrice<SelfReserve, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
268

            
269
impl cumulus_pallet_xcmp_queue::Config for Runtime {
270
    type RuntimeEvent = RuntimeEvent;
271
    type ChannelInfo = ParachainSystem;
272
    type VersionWrapper = PolkadotXcm;
273
    type ControllerOrigin = EnsureRoot<AccountId>;
274
    type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
275
    type WeightInfo = weights::cumulus_pallet_xcmp_queue::SubstrateWeight<Runtime>;
276
    type PriceForSiblingDelivery = PriceForSiblingParachainDelivery;
277
    type XcmpQueue = TransformOrigin<MessageQueue, AggregateMessageOrigin, ParaId, ParaIdToSibling>;
278
    type MaxInboundSuspended = sp_core::ConstU32<1_000>;
279
    type MaxActiveOutboundChannels = ConstU32<128>;
280
    type MaxPageSize = ConstU32<{ 103 * 1024 }>;
281
}
282

            
283
impl cumulus_pallet_xcm::Config for Runtime {
284
    type RuntimeEvent = RuntimeEvent;
285
    type XcmExecutor = XcmExecutor<XcmConfig>;
286
}
287

            
288
parameter_types! {
289
    pub MessageQueueServiceWeight: Weight = Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block;
290
}
291

            
292
impl pallet_message_queue::Config for Runtime {
293
    type RuntimeEvent = RuntimeEvent;
294
    type WeightInfo = weights::pallet_message_queue::SubstrateWeight<Self>;
295
    #[cfg(feature = "runtime-benchmarks")]
296
    type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor<
297
        cumulus_primitives_core::AggregateMessageOrigin,
298
    >;
299
    #[cfg(not(feature = "runtime-benchmarks"))]
300
    type MessageProcessor =
301
        xcm_builder::ProcessXcmMessage<AggregateMessageOrigin, XcmExecutor<XcmConfig>, RuntimeCall>;
302
    type Size = u32;
303
    // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin:
304
    type QueueChangeHandler = NarrowOriginToSibling<XcmpQueue>;
305
    // NarrowOriginToSibling calls XcmpQueue's is_pause if Origin is sibling. Allows all other origins
306
    type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling<XcmpQueue>);
307
    type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
308
    type MaxStale = sp_core::ConstU32<8>;
309
    type ServiceWeight = MessageQueueServiceWeight;
310
    type IdleMaxServiceWeight = MessageQueueServiceWeight;
311
}
312

            
313
parameter_types! {
314
    // we just reuse the same deposits
315
    pub const ForeignAssetsAssetDeposit: Balance = 0;
316
    pub const ForeignAssetsAssetAccountDeposit: Balance = 0;
317
    pub const ForeignAssetsApprovalDeposit: Balance = 0;
318
    pub const ForeignAssetsAssetsStringLimit: u32 = 50;
319
    pub const ForeignAssetsMetadataDepositBase: Balance = 0;
320
    pub const ForeignAssetsMetadataDepositPerByte: Balance = 0;
321
    pub CheckingAccount: AccountId = PolkadotXcm::check_account();
322
}
323

            
324
#[cfg(feature = "runtime-benchmarks")]
325
/// Simple conversion of `u32` into an `AssetId` for use in benchmarking.
326
pub struct ForeignAssetBenchmarkHelper;
327
#[cfg(feature = "runtime-benchmarks")]
328
impl pallet_assets::BenchmarkHelper<AssetId> for ForeignAssetBenchmarkHelper {
329
    fn create_asset_id_parameter(id: u32) -> AssetId {
330
        id.try_into()
331
            .expect("number too large to create benchmarks")
332
    }
333
}
334
#[cfg(feature = "runtime-benchmarks")]
335
impl pallet_asset_rate::AssetKindFactory<AssetId> for ForeignAssetBenchmarkHelper {
336
    fn create_asset_kind(id: u32) -> AssetId {
337
        id.try_into()
338
            .expect("number too large to create benchmarks")
339
    }
340
}
341

            
342
// Instruct how to go from an H160 to an AssetID
343
// We just take the lowest 2 bytes
344
impl AccountIdAssetIdConversion<AccountId, AssetId> for Runtime {
345
    /// The way to convert an account to assetId is by ensuring that the prefix is [0xFF, 18]
346
    /// and by taking the lowest 2 bytes as the assetId
347
    fn account_to_asset_id(account: AccountId) -> Option<(Vec<u8>, AssetId)> {
348
        let h160_account: H160 = account.into();
349
        let mut data = [0u8; 2];
350
        let (prefix_part, id_part) = h160_account.as_fixed_bytes().split_at(18);
351
        if prefix_part == FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX {
352
            data.copy_from_slice(id_part);
353
            let asset_id: AssetId = u16::from_be_bytes(data);
354
            Some((prefix_part.to_vec(), asset_id))
355
        } else {
356
            None
357
        }
358
    }
359

            
360
    // The opposite conversion
361
38
    fn asset_id_to_account(prefix: &[u8], asset_id: AssetId) -> AccountId {
362
38
        let mut data = [0u8; 20];
363
38
        data[0..18].copy_from_slice(prefix);
364
38
        data[18..20].copy_from_slice(&asset_id.to_be_bytes());
365
38
        AccountId::from(data)
366
38
    }
367
}
368

            
369
pub type AssetId = u16;
370
pub type ForeignAssetsInstance = pallet_assets::Instance1;
371
impl pallet_assets::Config<ForeignAssetsInstance> for Runtime {
372
    type RuntimeEvent = RuntimeEvent;
373
    type Balance = Balance;
374
    type AssetId = AssetId;
375
    type AssetIdParameter = AssetId;
376
    type Currency = Balances;
377
    type CreateOrigin = frame_support::traits::NeverEnsureOrigin<AccountId>;
378
    type ForceOrigin = EnsureRoot<AccountId>;
379
    type AssetDeposit = ForeignAssetsAssetDeposit;
380
    type MetadataDepositBase = ForeignAssetsMetadataDepositBase;
381
    type MetadataDepositPerByte = ForeignAssetsMetadataDepositPerByte;
382
    type ApprovalDeposit = ForeignAssetsApprovalDeposit;
383
    type StringLimit = ForeignAssetsAssetsStringLimit;
384
    type Freezer = ();
385
    type Extra = ();
386
    type WeightInfo = weights::pallet_assets::SubstrateWeight<Runtime>;
387
    type CallbackHandle = ();
388
    type AssetAccountDeposit = ForeignAssetsAssetAccountDeposit;
389
    type RemoveItemsLimit = frame_support::traits::ConstU32<1000>;
390
    type Holder = ();
391
    #[cfg(feature = "runtime-benchmarks")]
392
    type BenchmarkHelper = ForeignAssetBenchmarkHelper;
393
}
394

            
395
pub struct RevertCodePrecompileHook;
396

            
397
impl ForeignAssetCreatedHook<Location, AssetIdOf<Runtime>, AssetBalance<Runtime>>
398
    for RevertCodePrecompileHook
399
{
400
33
    fn on_asset_created(
401
33
        _foreign_asset: &Location,
402
33
        asset_id: &AssetIdOf<Runtime>,
403
33
        _min_balance: &AssetBalance<Runtime>,
404
33
    ) {
405
33
        let revert_bytecode = [0x60, 0x00, 0x60, 0x00, 0xFD].to_vec();
406
33
        let prefix_slice = [255u8; 18];
407
33
        let account_id = Runtime::asset_id_to_account(prefix_slice.as_slice(), *asset_id);
408
33

            
409
33
        let _ = pallet_evm::Pallet::<Runtime>::create_account(
410
33
            account_id.into(),
411
33
            revert_bytecode.clone(),
412
33
            None,
413
33
        );
414
33
    }
415
}
416

            
417
impl ForeignAssetDestroyedHook<Location, AssetIdOf<Runtime>> for RevertCodePrecompileHook {
418
    fn on_asset_destroyed(_foreign_asset: &Location, asset_id: &AssetIdOf<Runtime>) {
419
        let prefix_slice = [255u8; 18];
420
        let account_id = Runtime::asset_id_to_account(prefix_slice.as_slice(), *asset_id);
421

            
422
        pallet_evm::Pallet::<Runtime>::remove_account(&account_id.into());
423
    }
424
}
425

            
426
impl pallet_foreign_asset_creator::Config for Runtime {
427
    type RuntimeEvent = RuntimeEvent;
428
    type ForeignAsset = Location;
429
    type ForeignAssetCreatorOrigin = EnsureRoot<AccountId>;
430
    type ForeignAssetModifierOrigin = EnsureRoot<AccountId>;
431
    type ForeignAssetDestroyerOrigin = EnsureRoot<AccountId>;
432
    type Fungibles = ForeignAssets;
433
    type WeightInfo = weights::pallet_foreign_asset_creator::SubstrateWeight<Runtime>;
434
    type OnForeignAssetCreated = RevertCodePrecompileHook;
435
    type OnForeignAssetDestroyed = RevertCodePrecompileHook;
436
}
437

            
438
impl pallet_asset_rate::Config for Runtime {
439
    type CreateOrigin = EnsureRoot<AccountId>;
440
    type RemoveOrigin = EnsureRoot<AccountId>;
441
    type UpdateOrigin = EnsureRoot<AccountId>;
442
    type Currency = Balances;
443
    type AssetKind = AssetId;
444
    type RuntimeEvent = RuntimeEvent;
445
    type WeightInfo = weights::pallet_asset_rate::SubstrateWeight<Runtime>;
446
    #[cfg(feature = "runtime-benchmarks")]
447
    type BenchmarkHelper = ForeignAssetBenchmarkHelper;
448
}
449

            
450
parameter_types! {
451
    pub const TrustPolicyMaxAssets: u32 = 1000;
452
    pub const AllNativeTrustPolicy: DefaultTrustPolicy = DefaultTrustPolicy::AllNative;
453
    pub const AllNeverTrustPolicy: DefaultTrustPolicy = DefaultTrustPolicy::Never;
454
}
455
impl pallet_xcm_executor_utils::Config for Runtime {
456
    type RuntimeEvent = RuntimeEvent;
457
    type TrustPolicyMaxAssets = TrustPolicyMaxAssets;
458
    type ReserveDefaultTrustPolicy = AllNativeTrustPolicy;
459
    type SetReserveTrustOrigin = EnsureRoot<AccountId>;
460
    type TeleportDefaultTrustPolicy = AllNeverTrustPolicy;
461
    type SetTeleportTrustOrigin = EnsureRoot<AccountId>;
462
    type WeightInfo = weights::pallet_xcm_executor_utils::SubstrateWeight<Runtime>;
463
}
464

            
465
use {
466
    crate::ForeignAssets,
467
    xcm_builder::{FungiblesAdapter, NoChecking},
468
    xcm_executor::traits::JustTry,
469
};
470

            
471
/// Means for transacting foreign assets from different global consensus.
472
pub type ForeignFungiblesTransactor = FungiblesAdapter<
473
    // Use this fungibles implementation:
474
    ForeignAssets,
475
    // Use this currency when it is a fungible asset matching the given location or name:
476
    (ConvertedConcreteId<AssetId, Balance, ForeignAssetsCreator, JustTry>,),
477
    // Convert an XCM Location into a local account id:
478
    LocationToAccountId,
479
    // Our chain's account ID type (we can't get away without mentioning it explicitly):
480
    AccountId,
481
    // We dont need to check teleports here.
482
    NoChecking,
483
    // The account to use for tracking teleports.
484
    CheckingAccount,
485
>;
486

            
487
/// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance.
488
pub type AssetRateAsMultiplier =
489
    AssetFeeAsExistentialDepositMultiplier<Runtime, WeightToFee, AssetRate, ForeignAssetsInstance>;
490

            
491
#[test]
492
1
fn test_asset_id_to_account_conversion() {
493
1
    let prefix_slice = [255u8].repeat(18);
494
1
    let asset_ids_to_check = vec![0u16, 123u16, 3453u16, 10000u16, 65535u16];
495
6
    for current_asset_id in asset_ids_to_check {
496
5
        let account_id = Runtime::asset_id_to_account(prefix_slice.as_slice(), current_asset_id);
497
5
        assert_eq!(
498
5
            account_id.to_string().to_lowercase(),
499
5
            String::from("0xffffffffffffffffffffffffffffffffffff")
500
5
                + format!("{:04x}", current_asset_id).as_str()
501
5
        );
502
    }
503
1
}