Add Support for Foreign Assets (#2133)

* add foreign assets to westmint

* add foreign assets to statemine

* use updated api for ensure origin trait

* Assets/ForeignAssets tests and fixes (#2167)

* Test for create and transfer `TrustBackedAssets` with AssetTransactor

* Test for transfer `local Currency` with AssetTransactor

* Test for create foreign assets (covers foreign relaychain currency)

* Added `ForeignFungiblesTransactor` and test for transfer `ForeignAssets` with AssetTransactor

* Removed unused `pub const Local: MultiLocation`

* Changed `ParaId -> Sibling` for `SiblingParachainConvertsVia`

* Test for create foreign assets (covers local sibling parachain assets)

* Reverted stuff for ForeignCreators from different global consensus (moved to transfer asset branch)

* Refactor `weight_limit` for `execute_xcm`

* Added test for `set_metadata` by ForeignCreator with `xcm::Transact(set_metadata)`

* Renamed `receive_teleported_asset_works` -> `receive_teleported_asset_for_native_asset_works`

* Allow `ForeignCreators` only for sibling parachains

* Unify ReservedDmpWeight/ReservedXcmpWeight usage

* Removed hack - replaced with `MatchedConvertedConcreteId`

* Refactor `ForeignCreators` to assets-common

* Add `ReceiveTeleportedAsset` test

* Change test - `Utility::batch` -> Multiple `xcm::Transact`

* Reusing the same deposits as for TrustBackedAssets

* missing `try_successful_origin` ?

* Finished `ForeignAssets` for westmint (converter, FungiblesApi, tests)

* Refactoring tests - receive_teleported_asset_for_native_asset_works

* ForeignAssets for statemine + refactored `receive_teleported_asset_from_foreign_creator_works`

* Add `ForeignAssets` to statemine `FungiblesApi`

* Add `asset_transactor_transfer_with_local_consensus_currency_works` to all runtimes

* Added `asset_transactor_transfer_with_trust_backed_assets_works` test

* Added `asset_transactor_transfer_with_foreign_assets_works`

* Fix `missing `try_successful_origin` in implementation`

* Added `create_and_manage_foreign_assets_for_local_consensus_parachain_assets_works`

* Added `ExpectTransactStatus` check

* Small rename

* Extended `test_assets_balances_api_works` with ForeignAssets for `statemine`

* PR fixes

* Update parachains/runtimes/assets/test-utils/src/test_cases.rs

---------

Co-authored-by: parity-processbot <>
Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>

* Added `StartsWithExplicitGlobalConsensus` to ignores (#2338)

* Update parachains/runtimes/assets/common/src/lib.rs

Co-authored-by: Gavin Wood <gavin@parity.io>

* include mint and burn in SafeCallFilter

* include mint and burn in SafeCallFilter (statemine)

* clarify doc

* Fix compilation (moved trait `InspectMetadata`)

* Fix test

* Extended test for `teleport` from/to relaychain + `CheckingAccount` (Part I)

* Extended test for `teleport` from/to foreign parachain + `CheckingAccount` (Part II)

* Fixed TODO - `NonLocal` for `ForeignAssets`

* Changed `NonLocal` to `NoChecking`

* Fix weight in test

---------

Co-authored-by: parity-processbot <>
Co-authored-by: muharem <ismailov.m.h@gmail.com>
Co-authored-by: Branislav Kontur <bkontur@gmail.com>
Co-authored-by: Gavin Wood <gavin@parity.io>
This commit is contained in:
joe petrowski
2023-03-23 15:14:27 +01:00
committed by GitHub
parent 44126eb857
commit af46f4b41e
25 changed files with 2865 additions and 237 deletions
@@ -66,19 +66,23 @@ use parachains_common::{
NORMAL_DISPATCH_RATIO, SLOT_DURATION,
};
use xcm_config::{
FellowshipLocation, GovernanceLocation, KsmLocation, TrustBackedAssetsConvertedConcreteId,
XcmConfig,
FellowshipLocation, ForeignAssetsConvertedConcreteId, GovernanceLocation, KsmLocation,
TrustBackedAssetsConvertedConcreteId, XcmConfig,
};
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
// Polkadot imports
use assets_common::{
foreign_creators::ForeignCreators, matching::FromSiblingParachain, MultiLocationForAssetId,
};
use pallet_xcm::{EnsureXcm, IsVoiceOfBody};
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! {
@@ -264,6 +268,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);
@@ -336,6 +382,7 @@ impl Default for ProxyType {
Self::Any
}
}
impl InstanceFilter<RuntimeCall> for ProxyType {
fn filter(&self, c: &RuntimeCall) -> bool {
match self {
@@ -689,6 +736,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,
#[cfg(feature = "state-trie-version-1")]
StateTrieMigration: pallet_state_trie_migration = 70,
@@ -741,6 +789,7 @@ mod benches {
define_benchmarks!(
[frame_system, SystemBench::<Runtime>]
[pallet_assets, Assets]
[pallet_assets, ForeignAssets]
[pallet_balances, Balances]
[pallet_multisig, Multisig]
[pallet_nfts, Nfts]
@@ -916,11 +965,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 ... e.g. pallet_assets ForeignAssets
// collect pallet_assets (ForeignAssets)
convert::<_, _, _, _, ForeignAssetsConvertedConcreteId>(
ForeignAssets::account_balances(account)
.iter()
.filter(|(_, balance)| balance > &0)
)?,
// collect ... e.g. other tokens
].concat())
}
}
@@ -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},
@@ -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,
};
@@ -49,7 +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 const Local: MultiLocation = Here.into_location();
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();
@@ -83,7 +86,7 @@ pub type CurrencyTransactor = CurrencyAdapter<
(),
>;
/// `AssetId/Balancer` converter for `TrustBackedAssets`
/// `AssetId/Balance` converter for `TrustBackedAssets`
pub type TrustBackedAssetsConvertedConcreteId =
assets_common::TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance>;
@@ -103,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 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
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
@@ -213,6 +246,35 @@ impl Contains<RuntimeCall> for SafeCallFilter {
pallet_assets::Call::touch { .. } |
pallet_assets::Call::refund { .. },
) |
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 { .. } |
@@ -322,7 +384,13 @@ impl xcm_executor::Config for XcmConfig {
// Statemine acting _as_ a reserve location for KSM and assets created under `pallet-assets`.
// For KSM, users must use teleport where allowed (e.g. with the Relay Chain).
type IsReserve = ();
type IsTeleporter = NativeAsset; // <- should be enough to allow teleportation of KSM
// We allow:
// - teleportation of KSM
// - 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<
@@ -415,3 +483,20 @@ 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")]
use pallet_assets::BenchmarkHelper;
#[cfg(feature = "runtime-benchmarks")]
impl BenchmarkHelper<MultiLocation> for XcmBenchmarkHelper {
fn create_asset_id_parameter(id: u32) -> MultiLocation {
MultiLocation { parents: 1, interior: X1(Parachain(id)) }
}
}