Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Add Foreign Assets to Statemint (#2540)
Browse files Browse the repository at this point in the history
* add foreign assets to statemint

* make review changes

* two dots

---------

Co-authored-by: parity-processbot <>
  • Loading branch information
joepetrowski authored May 23, 2023
1 parent 6cf3618 commit 415dd81
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 31 deletions.
10 changes: 4 additions & 6 deletions parachains/runtimes/assets/statemine/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConverte
(
// Ignore `TrustBackedAssets` explicitly
StartsWith<TrustBackedAssetsPalletLocation>,
// Ignore asset which starts explicitly with our `GlobalConsensus(NetworkId)`, means:
// - foreign assets from our consensus should be: `MultiLocation {parent: 1, X*(Parachain(xyz))}
// - foreign assets outside our consensus with the same `GlobalConsensus(NetworkId)` wont be accepted here
// Ignore assets that start explicitly with our `GlobalConsensus(NetworkId)`, means:
// - foreign assets from our consensus should be: `MultiLocation {parents: 1, X*(Parachain(xyz), ..)}`
// - foreign assets outside our consensus with the same `GlobalConsensus(NetworkId)` won't be accepted here
StartsWithExplicitGlobalConsensus<UniversalLocationNetworkId>,
),
Balance,
Expand Down Expand Up @@ -491,9 +491,7 @@ pub type ForeignCreatorsSovereignAccountOf = (
/// Simple conversion of `u32` into an `AssetId` for use in benchmarking.
pub struct XcmBenchmarkHelper;
#[cfg(feature = "runtime-benchmarks")]
use pallet_assets::BenchmarkHelper;
#[cfg(feature = "runtime-benchmarks")]
impl BenchmarkHelper<MultiLocation> for XcmBenchmarkHelper {
impl pallet_assets::BenchmarkHelper<MultiLocation> for XcmBenchmarkHelper {
fn create_asset_id_parameter(id: u32) -> MultiLocation {
MultiLocation { parents: 1, interior: X1(Parachain(id)) }
}
Expand Down
62 changes: 58 additions & 4 deletions parachains/runtimes/assets/statemint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ pub mod constants;
mod weights;
pub mod xcm_config;

use assets_common::{
foreign_creators::ForeignCreators, matching::FromSiblingParachain, MultiLocationForAssetId,
};
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
Expand Down Expand Up @@ -95,8 +98,8 @@ use parachains_common::{
MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION,
};
use xcm_config::{
DotLocation, FellowshipLocation, GovernanceLocation, TrustBackedAssetsConvertedConcreteId,
XcmConfig, XcmOriginToTransactDispatchOrigin,
DotLocation, FellowshipLocation, ForeignAssetsConvertedConcreteId, GovernanceLocation,
TrustBackedAssetsConvertedConcreteId, XcmConfig, XcmOriginToTransactDispatchOrigin,
};

#[cfg(any(feature = "std", test))]
Expand All @@ -108,6 +111,7 @@ use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
use xcm::latest::BodyId;
use xcm_executor::XcmExecutor;

use crate::xcm_config::ForeignCreatorsSovereignAccountOf;
use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight};

impl_opaque_keys! {
Expand Down Expand Up @@ -279,6 +283,48 @@ impl pallet_assets::Config<TrustBackedAssetsInstance> for Runtime {
type BenchmarkHelper = ();
}

parameter_types! {
// we just reuse the same deposits
pub const ForeignAssetsAssetDeposit: Balance = AssetDeposit::get();
pub const ForeignAssetsAssetAccountDeposit: Balance = AssetAccountDeposit::get();
pub const ForeignAssetsApprovalDeposit: Balance = ApprovalDeposit::get();
pub const ForeignAssetsAssetsStringLimit: u32 = AssetsStringLimit::get();
pub const ForeignAssetsMetadataDepositBase: Balance = MetadataDepositBase::get();
pub const ForeignAssetsMetadataDepositPerByte: Balance = MetadataDepositPerByte::get();
}

/// Assets managed by some foreign location. Note: we do not declare a `ForeignAssetsCall` type, as
/// this type is used in proxy definitions. We assume that a foreign location would not want to set
/// an individual, local account as a proxy for the issuance of their assets. This issuance should
/// be managed by the foreign location's governance.
pub type ForeignAssetsInstance = pallet_assets::Instance2;
impl pallet_assets::Config<ForeignAssetsInstance> for Runtime {
type RuntimeEvent = RuntimeEvent;
type Balance = Balance;
type AssetId = MultiLocationForAssetId;
type AssetIdParameter = MultiLocationForAssetId;
type Currency = Balances;
type CreateOrigin = ForeignCreators<
(FromSiblingParachain<parachain_info::Pallet<Runtime>>,),
ForeignCreatorsSovereignAccountOf,
AccountId,
>;
type ForceOrigin = AssetsForceOrigin;
type AssetDeposit = ForeignAssetsAssetDeposit;
type MetadataDepositBase = ForeignAssetsMetadataDepositBase;
type MetadataDepositPerByte = ForeignAssetsMetadataDepositPerByte;
type ApprovalDeposit = ForeignAssetsApprovalDeposit;
type StringLimit = ForeignAssetsAssetsStringLimit;
type Freezer = ();
type Extra = ();
type WeightInfo = weights::pallet_assets::WeightInfo<Runtime>;
type CallbackHandle = ();
type AssetAccountDeposit = ForeignAssetsAssetAccountDeposit;
type RemoveItemsLimit = frame_support::traits::ConstU32<1000>;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = xcm_config::XcmBenchmarkHelper;
}

parameter_types! {
// One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes.
pub const DepositBase: Balance = deposit(1, 88);
Expand Down Expand Up @@ -704,6 +750,7 @@ construct_runtime!(
Assets: pallet_assets::<Instance1>::{Pallet, Call, Storage, Event<T>} = 50,
Uniques: pallet_uniques::{Pallet, Call, Storage, Event<T>} = 51,
Nfts: pallet_nfts::{Pallet, Call, Storage, Event<T>} = 52,
ForeignAssets: pallet_assets::<Instance2>::{Pallet, Call, Storage, Event<T>} = 53,
}
);

Expand Down Expand Up @@ -753,6 +800,7 @@ mod benches {
define_benchmarks!(
[frame_system, SystemBench::<Runtime>]
[pallet_assets, Assets]
[pallet_assets, ForeignAssets]
[pallet_balances, Balances]
[pallet_multisig, Multisig]
[pallet_nfts, Nfts]
Expand Down Expand Up @@ -928,11 +976,17 @@ impl_runtime_apis! {
},
// collect pallet_assets (TrustBackedAssets)
convert::<_, _, _, _, TrustBackedAssetsConvertedConcreteId>(
Assets::account_balances(account)
Assets::account_balances(account.clone())
.iter()
.filter(|(_, balance)| balance > &0)
)?,
// collect pallet_assets (ForeignAssets)
convert::<_, _, _, _, ForeignAssetsConvertedConcreteId>(
ForeignAssets::account_balances(account)
.iter()
.filter(|(_, balance)| balance > &0)
)?,
// collect ... e.g. pallet_assets ForeignAssets
// collect ... e.g. other tokens
].concat().into())
}
}
Expand Down
98 changes: 91 additions & 7 deletions parachains/runtimes/assets/statemint/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
// limitations under the License.

use super::{
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ParachainInfo,
ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ForeignAssets,
ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
};
use assets_common::matching::{
FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus,
};
use frame_support::{
match_types, parameter_types,
traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess},
Expand All @@ -36,8 +39,8 @@ use xcm::latest::prelude::*;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, EnsureXcmOrigin,
FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, ParentAsSuperuser, ParentIsPreset,
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, NoChecking, ParentAsSuperuser,
ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
UsingComponents, WeightInfoBounds, WithComputedOrigin,
};
Expand All @@ -49,6 +52,7 @@ parameter_types! {
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
pub UniversalLocation: InteriorMultiLocation =
X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into()));
pub UniversalLocationNetworkId: NetworkId = UniversalLocation::get().global_consensus().unwrap();
pub TrustBackedAssetsPalletLocation: MultiLocation =
PalletInstance(<Assets as PalletInfoAccess>::index() as u8).into();
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
Expand Down Expand Up @@ -102,8 +106,38 @@ pub type FungiblesTransactor = FungiblesAdapter<
// The account to use for tracking teleports.
CheckingAccount,
>;

/// `AssetId/Balance` converter for `TrustBackedAssets`
pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId<
(
// Ignore `TrustBackedAssets` explicitly
StartsWith<TrustBackedAssetsPalletLocation>,
// Ignore assets that start explicitly with our `GlobalConsensus(NetworkId)`, means:
// - foreign assets from our consensus should be: `MultiLocation {parents: 1, X*(Parachain(xyz), ..)}`
// - foreign assets outside our consensus with the same `GlobalConsensus(NetworkId)` won't be accepted here
StartsWithExplicitGlobalConsensus<UniversalLocationNetworkId>,
),
Balance,
>;

/// Means for transacting foreign assets from different global consensus.
pub type ForeignFungiblesTransactor = FungiblesAdapter<
// Use this fungibles implementation:
ForeignAssets,
// Use this currency when it is a fungible asset matching the given location or name:
ForeignAssetsConvertedConcreteId,
// Convert an XCM MultiLocation into a local account id:
LocationToAccountId,
// Our chain's account ID type (we can't get away without mentioning it explicitly):
AccountId,
// We dont need to check teleports here.
NoChecking,
// The account to use for tracking teleports.
CheckingAccount,
>;

/// Means for transacting assets on this chain.
pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor);
pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor, ForeignFungiblesTransactor);

/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
Expand Down Expand Up @@ -205,6 +239,7 @@ impl Contains<RuntimeCall> for SafeCallFilter {
pallet_assets::Call::thaw_asset { .. } |
pallet_assets::Call::transfer_ownership { .. } |
pallet_assets::Call::set_team { .. } |
pallet_assets::Call::set_metadata { .. } |
pallet_assets::Call::clear_metadata { .. } |
pallet_assets::Call::force_clear_metadata { .. } |
pallet_assets::Call::force_asset_status { .. } |
Expand All @@ -214,7 +249,35 @@ impl Contains<RuntimeCall> for SafeCallFilter {
pallet_assets::Call::transfer_approved { .. } |
pallet_assets::Call::touch { .. } |
pallet_assets::Call::refund { .. },
) | RuntimeCall::Nfts(
) | RuntimeCall::ForeignAssets(
pallet_assets::Call::create { .. } |
pallet_assets::Call::force_create { .. } |
pallet_assets::Call::start_destroy { .. } |
pallet_assets::Call::destroy_accounts { .. } |
pallet_assets::Call::destroy_approvals { .. } |
pallet_assets::Call::finish_destroy { .. } |
pallet_assets::Call::mint { .. } |
pallet_assets::Call::burn { .. } |
pallet_assets::Call::transfer { .. } |
pallet_assets::Call::transfer_keep_alive { .. } |
pallet_assets::Call::force_transfer { .. } |
pallet_assets::Call::freeze { .. } |
pallet_assets::Call::thaw { .. } |
pallet_assets::Call::freeze_asset { .. } |
pallet_assets::Call::thaw_asset { .. } |
pallet_assets::Call::transfer_ownership { .. } |
pallet_assets::Call::set_team { .. } |
pallet_assets::Call::set_metadata { .. } |
pallet_assets::Call::clear_metadata { .. } |
pallet_assets::Call::force_clear_metadata { .. } |
pallet_assets::Call::force_asset_status { .. } |
pallet_assets::Call::approve_transfer { .. } |
pallet_assets::Call::cancel_approval { .. } |
pallet_assets::Call::force_cancel_approval { .. } |
pallet_assets::Call::transfer_approved { .. } |
pallet_assets::Call::touch { .. } |
pallet_assets::Call::refund { .. },
) | RuntimeCall::Nfts(
pallet_nfts::Call::create { .. } |
pallet_nfts::Call::force_create { .. } |
pallet_nfts::Call::destroy { .. } |
Expand Down Expand Up @@ -321,7 +384,13 @@ impl xcm_executor::Config for XcmConfig {
// Statemint acting _as_ a reserve location for DOT and assets created under `pallet-assets`.
// For DOT, users must use teleport where allowed (e.g. with the Relay Chain).
type IsReserve = ();
type IsTeleporter = NativeAsset; // <- should be enough to allow teleportation of DOT
// We allow:
// - teleportation of DOT
// - teleportation of sibling parachain's assets (as ForeignCreators)
type IsTeleporter = (
NativeAsset,
IsForeignConcreteAsset<FromSiblingParachain<parachain_info::Pallet<Runtime>>>,
);
type UniversalLocation = UniversalLocation;
type Barrier = Barrier;
type Weigher = WeightInfoBounds<
Expand Down Expand Up @@ -415,3 +484,18 @@ impl cumulus_pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type XcmExecutor = XcmExecutor<XcmConfig>;
}

pub type ForeignCreatorsSovereignAccountOf = (
SiblingParachainConvertsVia<Sibling, AccountId>,
AccountId32Aliases<RelayNetwork, AccountId>,
ParentIsPreset<AccountId>,
);

/// Simple conversion of `u32` into an `AssetId` for use in benchmarking.
pub struct XcmBenchmarkHelper;
#[cfg(feature = "runtime-benchmarks")]
impl pallet_assets::BenchmarkHelper<MultiLocation> for XcmBenchmarkHelper {
fn create_asset_id_parameter(id: u32) -> MultiLocation {
MultiLocation { parents: 1, interior: X1(Parachain(id)) }
}
}
Loading

0 comments on commit 415dd81

Please sign in to comment.