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

Add Foreign Assets to Statemint #2540

Merged
merged 6 commits into from
May 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>,
muharem marked this conversation as resolved.
Show resolved Hide resolved
);

/// 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