Companion for #13352 (#2180)

* Assets balances

* Update docs

* AssetsApi with MultiLocation as preparation for multi pallet_assets instances (#2187)

* AssetsApi with MultiLocation for Westmint + assets-common

* AssetsApi with MultiLocation for Statemine/t

* typo

* typo for check-docs job

* WIP: AssetsApi return MultiAsset instead of (MultiLocation, Balance)

* WIP: assets_api + conversion refactor

* WIP: assets_api + conversion refactor

* Finished asset runtimes

* Refactor AssetsApi to FungiblesApi

* Refactor

* Fix check-rust-docs

* Removed todo

* Fix check-rust-doc

* Update parachains/runtimes/assets/common/Cargo.toml

Co-authored-by: Bastian Köcher <git@kchr.de>

* update lockfile for {"substrate", "polkadot"}

---------

Co-authored-by: Branislav Kontur <bkontur@gmail.com>
Co-authored-by: parity-processbot <>
Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
Jegor Sidorenko
2023-03-02 16:37:18 +02:00
committed by GitHub
parent 47046d798c
commit 2156cbc046
18 changed files with 917 additions and 466 deletions
+208 -190
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -35,6 +35,7 @@ members = [
"parachains/runtimes/testing/rococo-parachain",
"parachains/runtimes/starters/shell",
"parachains/runtimes/starters/seedling",
"parachains/runtimes/assets/common",
"parachains/runtimes/assets/statemint",
"parachains/runtimes/assets/statemine",
"parachains/runtimes/assets/westmint",
@@ -0,0 +1,38 @@
[package]
name = "assets-common"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"
description = "Assets common utilities"
[dependencies]
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
# Substrate
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
# Polkadot
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
# Cumulus
parachains-common = { path = "../../../common", default-features = false }
[build-dependencies]
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
[features]
default = [ "std" ]
std = [
"codec/std",
"frame-support/std",
"parachains-common/std",
"sp-api/std",
"sp-std/std",
"xcm/std",
"xcm-builder/std",
"xcm-executor/std",
]
@@ -0,0 +1,136 @@
// This file is part of Substrate.
// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Runtime API definition for assets.
use crate::runtime_api::FungiblesAccessError;
use sp_std::{borrow::Borrow, vec::Vec};
use xcm::latest::{MultiAsset, MultiLocation};
use xcm_builder::ConvertedConcreteId;
use xcm_executor::traits::{Convert, MatchesFungibles};
/// Converting any [`(AssetId, Balance)`] to [`MultiAsset`]
pub trait MultiAssetConverter<AssetId, Balance, ConvertAssetId, ConvertBalance>:
MatchesFungibles<AssetId, Balance>
where
AssetId: Clone,
Balance: Clone,
ConvertAssetId: Convert<MultiLocation, AssetId>,
ConvertBalance: Convert<u128, Balance>,
{
fn convert_ref(
value: impl Borrow<(AssetId, Balance)>,
) -> Result<MultiAsset, FungiblesAccessError>;
}
impl<
AssetId: Clone,
Balance: Clone,
ConvertAssetId: Convert<MultiLocation, AssetId>,
ConvertBalance: Convert<u128, Balance>,
> MultiAssetConverter<AssetId, Balance, ConvertAssetId, ConvertBalance>
for ConvertedConcreteId<AssetId, Balance, ConvertAssetId, ConvertBalance>
{
fn convert_ref(
value: impl Borrow<(AssetId, Balance)>,
) -> Result<MultiAsset, FungiblesAccessError> {
let (asset_id, balance) = value.borrow();
match ConvertAssetId::reverse_ref(asset_id) {
Ok(asset_id_as_multilocation) => match ConvertBalance::reverse_ref(balance) {
Ok(amount) => Ok((asset_id_as_multilocation, amount).into()),
Err(_) => Err(FungiblesAccessError::AmountToBalanceConversionFailed),
},
Err(_) => Err(FungiblesAccessError::AssetIdConversionFailed),
}
}
}
/// Helper function to convert collections with [`(AssetId, Balance)`] to [`MultiAsset`]
pub fn convert<'a, AssetId, Balance, ConvertAssetId, ConvertBalance, Converter>(
items: impl Iterator<Item = &'a (AssetId, Balance)>,
) -> Result<Vec<MultiAsset>, FungiblesAccessError>
where
AssetId: Clone + 'a,
Balance: Clone + 'a,
ConvertAssetId: Convert<MultiLocation, AssetId>,
ConvertBalance: Convert<u128, Balance>,
Converter: MultiAssetConverter<AssetId, Balance, ConvertAssetId, ConvertBalance>,
{
items.map(Converter::convert_ref).collect()
}
/// Helper function to convert `Balance` with MultiLocation` to `MultiAsset`
pub fn convert_balance<
T: frame_support::pallet_prelude::Get<MultiLocation>,
Balance: TryInto<u128>,
>(
balance: Balance,
) -> Result<MultiAsset, FungiblesAccessError> {
match balance.try_into() {
Ok(balance) => Ok((T::get(), balance).into()),
Err(_) => Err(FungiblesAccessError::AmountToBalanceConversionFailed),
}
}
#[cfg(test)]
mod tests {
use super::*;
use xcm::latest::prelude::*;
use xcm_executor::traits::{Identity, JustTry};
type Converter = ConvertedConcreteId<MultiLocation, u64, Identity, JustTry>;
#[test]
fn converted_concrete_id_fungible_multi_asset_conversion_roundtrip_works() {
let location = MultiLocation::new(0, X1(GlobalConsensus(ByGenesis([0; 32]))));
let amount = 123456_u64;
let expected_multi_asset = MultiAsset {
id: Concrete(MultiLocation::new(0, X1(GlobalConsensus(ByGenesis([0; 32]))))),
fun: Fungible(123456_u128),
};
assert_eq!(
Converter::matches_fungibles(&expected_multi_asset).map_err(|_| ()),
Ok((location, amount))
);
assert_eq!(Converter::convert_ref((location, amount)), Ok(expected_multi_asset));
}
#[test]
fn converted_concrete_id_fungible_multi_asset_conversion_collection_works() {
let data = vec![
(MultiLocation::new(0, X1(GlobalConsensus(ByGenesis([0; 32])))), 123456_u64),
(MultiLocation::new(1, X1(GlobalConsensus(ByGenesis([1; 32])))), 654321_u64),
];
let expected_data = vec![
MultiAsset {
id: Concrete(MultiLocation::new(0, X1(GlobalConsensus(ByGenesis([0; 32]))))),
fun: Fungible(123456_u128),
},
MultiAsset {
id: Concrete(MultiLocation::new(1, X1(GlobalConsensus(ByGenesis([1; 32]))))),
fun: Fungible(654321_u128),
},
];
assert_eq!(convert::<_, _, _, _, Converter>(data.iter()), Ok(expected_data));
}
}
@@ -0,0 +1,70 @@
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![cfg_attr(not(feature = "std"), no_std)]
pub mod fungible_conversion;
pub mod runtime_api;
use parachains_common::AssetIdForTrustBackedAssets;
use xcm_builder::{AsPrefixedGeneralIndex, ConvertedConcreteId};
use xcm_executor::traits::JustTry;
/// `MultiLocation` vs `AssetIdForTrustBackedAssets` converter for `TrustBackedAssets`
pub type AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation> =
AsPrefixedGeneralIndex<TrustBackedAssetsPalletLocation, AssetIdForTrustBackedAssets, JustTry>;
/// [`ConvertedConcreteId`] converter dedicated for `TrustBackedAssets`
pub type TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance> =
ConvertedConcreteId<
AssetIdForTrustBackedAssets,
Balance,
AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>,
JustTry,
>;
#[cfg(test)]
mod tests {
use super::*;
use xcm::latest::prelude::*;
use xcm_executor::traits::Convert;
frame_support::parameter_types! {
pub TrustBackedAssetsPalletLocation: MultiLocation = MultiLocation::new(5, X1(PalletInstance(13)));
}
#[test]
fn asset_id_for_trust_backed_assets_convert_works() {
let local_asset_id = 123456789 as AssetIdForTrustBackedAssets;
let expected_reverse_ref =
MultiLocation::new(5, X2(PalletInstance(13), GeneralIndex(local_asset_id.into())));
assert_eq!(
AssetIdForTrustBackedAssetsConvert::<TrustBackedAssetsPalletLocation>::reverse_ref(
local_asset_id
)
.unwrap(),
expected_reverse_ref
);
assert_eq!(
AssetIdForTrustBackedAssetsConvert::<TrustBackedAssetsPalletLocation>::convert_ref(
expected_reverse_ref
)
.unwrap(),
local_asset_id
);
}
}
@@ -0,0 +1,41 @@
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Runtime API definition for fungibles.
use codec::{Codec, Decode, Encode};
use frame_support::RuntimeDebug;
use sp_std::vec::Vec;
use xcm::latest::MultiAsset;
/// The possible errors that can happen querying the storage of assets.
#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)]
pub enum FungiblesAccessError {
/// `MultiLocation` to `AssetId`/`ClassId` conversion failed.
AssetIdConversionFailed,
/// `u128` amount to currency `Balance` conversion failed.
AmountToBalanceConversionFailed,
}
sp_api::decl_runtime_apis! {
/// The API for querying account's balances from runtime.
pub trait FungiblesApi<AccountId>
where
AccountId: Codec,
{
/// Returns the list of all [`MultiAsset`] that an `AccountId` has.
fn query_account_balances(account: AccountId) -> Result<Vec<MultiAsset>, FungiblesAccessError>;
}
}
@@ -49,6 +49,7 @@ pallet-state-trie-migration = { git = "https://github.com/paritytech/substrate",
# Polkadot
kusama-runtime-constants = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true }
polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
@@ -69,8 +70,7 @@ cumulus-primitives-utility = { path = "../../../../primitives/utility", default-
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
parachain-info = { path = "../../../pallets/parachain-info", default-features = false }
parachains-common = { path = "../../../common", default-features = false }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true }
assets-common = { path = "../common", default-features = false }
[dev-dependencies]
asset-test-utils = { path = "../test-utils"}
@@ -187,4 +187,5 @@ std = [
"pallet-collator-selection/std",
"parachain-info/std",
"parachains-common/std",
"assets-common/std",
]
@@ -64,7 +64,7 @@ use parachains_common::{
Index, Signature, AVERAGE_ON_INITIALIZE_RATIO, HOURS, MAXIMUM_BLOCK_WEIGHT,
NORMAL_DISPATCH_RATIO, SLOT_DURATION,
};
use xcm_config::{KsmLocation, XcmConfig};
use xcm_config::{KsmLocation, TrustBackedAssetsConvertedConcreteId, XcmConfig};
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
@@ -831,6 +831,34 @@ impl_runtime_apis! {
}
}
impl assets_common::runtime_api::FungiblesApi<
Block,
AccountId,
> for Runtime
{
fn query_account_balances(account: AccountId) -> Result<Vec<xcm::latest::MultiAsset>, assets_common::runtime_api::FungiblesAccessError> {
use assets_common::fungible_conversion::{convert, convert_balance};
Ok([
// collect pallet_balance
{
let balance = Balances::free_balance(account.clone());
if balance > 0 {
vec![convert_balance::<KsmLocation, Balance>(balance)?]
} else {
vec![]
}
},
// collect pallet_assets (TrustBackedAssets)
convert::<_, _, _, _, TrustBackedAssetsConvertedConcreteId>(
Assets::account_balances(account)
.iter()
.filter(|(_, balance)| balance > &0)
)?,
// collect ... e.g. pallet_assets ForeignAssets
].concat())
}
}
impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
fn collect_collation_info(header: &<Block as BlockT>::Header) -> cumulus_primitives_core::CollationInfo {
ParachainSystem::collect_collation_info(header)
@@ -14,9 +14,9 @@
// limitations under the License.
use super::{
AccountId, AllPalletsWithSystem, AssetIdForTrustBackedAssets, Assets, Authorship, Balance,
Balances, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent,
RuntimeOrigin, TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ParachainInfo,
ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
};
use frame_support::{
match_types, parameter_types,
@@ -34,17 +34,13 @@ use sp_runtime::traits::ConvertInto;
use xcm::latest::prelude::*;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex,
ConvertedConcreteId, CurrencyAdapter, EnsureXcmOrigin, FungiblesAdapter, IsConcrete, LocalMint,
NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, WeightInfoBounds,
WithComputedOrigin,
};
use xcm_executor::{
traits::{JustTry, WithOriginFilter},
XcmExecutor,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, EnsureXcmOrigin,
FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, ParentAsSuperuser, ParentIsPreset,
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
UsingComponents, WeightInfoBounds, WithComputedOrigin,
};
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
parameter_types! {
pub const KsmLocation: MultiLocation = MultiLocation::parent();
@@ -84,21 +80,16 @@ pub type CurrencyTransactor = CurrencyAdapter<
(),
>;
/// `AssetId/Balancer` converter for `TrustBackedAssets`
pub type TrustBackedAssetsConvertedConcreteId =
assets_common::TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance>;
/// Means for transacting assets besides the native currency on this chain.
pub type FungiblesTransactor = FungiblesAdapter<
// Use this fungibles implementation:
Assets,
// Use this currency when it is a fungible asset matching the given location or name:
ConvertedConcreteId<
AssetIdForTrustBackedAssets,
Balance,
AsPrefixedGeneralIndex<
TrustBackedAssetsPalletLocation,
AssetIdForTrustBackedAssets,
JustTry,
>,
JustTry,
>,
TrustBackedAssetsConvertedConcreteId,
// 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):
@@ -302,16 +293,7 @@ impl xcm_executor::Config for XcmConfig {
cumulus_primitives_utility::TakeFirstAssetTrader<
AccountId,
AssetFeeAsExistentialDepositMultiplierFeeCharger,
ConvertedConcreteId<
AssetIdForTrustBackedAssets,
Balance,
AsPrefixedGeneralIndex<
TrustBackedAssetsPalletLocation,
AssetIdForTrustBackedAssets,
JustTry,
>,
JustTry,
>,
TrustBackedAssetsConvertedConcreteId,
Assets,
cumulus_primitives_utility::XcmFeesTo32ByteAccount<
FungiblesTransactor,
@@ -3,20 +3,27 @@ use codec::Encode;
use cumulus_primitives_utility::ChargeWeightInFungibles;
use frame_support::{
assert_noop, assert_ok, sp_io,
traits::PalletInfo,
weights::{Weight, WeightToFee as WeightToFeeT},
};
use parachains_common::{AccountId, AuraId};
use statemine_runtime::xcm_config::AssetFeeAsExistentialDepositMultiplierFeeCharger;
use parachains_common::{AccountId, AuraId, Balance};
use statemine_runtime::xcm_config::{
AssetFeeAsExistentialDepositMultiplierFeeCharger, KsmLocation, TrustBackedAssetsPalletLocation,
};
pub use statemine_runtime::{
constants::fee::WeightToFee, xcm_config::XcmConfig, Assets, Balances, ExistentialDeposit,
ReservedDmpWeight, Runtime, SessionKeys, System,
};
use xcm::latest::prelude::*;
use xcm_executor::{traits::WeightTrader, XcmExecutor};
use xcm_executor::{
traits::{Convert, WeightTrader},
XcmExecutor,
};
pub const ALICE: [u8; 32] = [1u8; 32];
type AssetIdForTrustBackedAssetsConvert =
assets_common::AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>;
#[test]
fn test_asset_xcm_trader() {
ExtBuilder::<Runtime>::default()
@@ -48,16 +55,8 @@ fn test_asset_xcm_trader() {
));
// get asset id as multilocation
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(local_asset_id.into()),
),
);
let asset_multilocation =
AssetIdForTrustBackedAssetsConvert::reverse_ref(local_asset_id).unwrap();
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
@@ -95,12 +94,15 @@ fn test_asset_xcm_trader() {
// Make sure author(Alice) has received the amount
assert_eq!(
Assets::balance(1, AccountId::from(ALICE)),
Assets::balance(local_asset_id, AccountId::from(ALICE)),
minimum_asset_balance + asset_amount_needed
);
// We also need to ensure the total supply increased
assert_eq!(Assets::total_supply(1), minimum_asset_balance + asset_amount_needed);
assert_eq!(
Assets::total_supply(local_asset_id),
minimum_asset_balance + asset_amount_needed
);
});
}
@@ -141,16 +143,7 @@ fn test_asset_xcm_trader_with_refund() {
// We are going to buy 4e9 weight
let bought = Weight::from_ref_time(4_000_000_000u64);
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(1),
),
);
let asset_multilocation = AssetIdForTrustBackedAssetsConvert::reverse_ref(1).unwrap();
// lets calculate amount needed
let amount_bought = WeightToFee::weight_to_fee(&bought);
@@ -219,16 +212,7 @@ fn test_asset_xcm_trader_refund_not_possible_since_amount_less_than_ed() {
// We are going to buy small amount
let bought = Weight::from_ref_time(500_000_000u64);
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(1),
),
);
let asset_multilocation = AssetIdForTrustBackedAssetsConvert::reverse_ref(1).unwrap();
let amount_bought = WeightToFee::weight_to_fee(&bought);
@@ -279,16 +263,7 @@ fn test_that_buying_ed_refund_does_not_refund() {
// We are gonna buy ED
let bought = Weight::from_ref_time(ExistentialDeposit::get().try_into().unwrap());
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(1),
),
);
let asset_multilocation = AssetIdForTrustBackedAssetsConvert::reverse_ref(1).unwrap();
let amount_bought = WeightToFee::weight_to_fee(&bought);
@@ -363,16 +338,7 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
// lets calculate amount needed
let asset_amount_needed = WeightToFee::weight_to_fee(&bought);
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(1),
),
);
let asset_multilocation = AssetIdForTrustBackedAssetsConvert::reverse_ref(1).unwrap();
let asset: MultiAsset = (asset_multilocation, asset_amount_needed).into();
@@ -390,6 +356,75 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
});
}
#[test]
fn test_assets_balances_api_works() {
use assets_common::runtime_api::runtime_decl_for_FungiblesApi::FungiblesApi;
ExtBuilder::<Runtime>::default()
.with_collators(vec![AccountId::from(ALICE)])
.with_session_keys(vec![(
AccountId::from(ALICE),
AccountId::from(ALICE),
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) },
)])
.build()
.execute_with(|| {
let local_asset_id = 1;
// check before
assert_eq!(Assets::balance(local_asset_id, AccountId::from(ALICE)), 0);
assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 0);
assert!(Runtime::query_account_balances(AccountId::from(ALICE)).unwrap().is_empty());
// Drip some balance
use frame_support::traits::fungible::Mutate;
let some_currency = ExistentialDeposit::get();
Balances::mint_into(&AccountId::from(ALICE), some_currency).unwrap();
// We need root origin to create a sufficient asset
let minimum_asset_balance = 3333333_u128;
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
local_asset_id.into(),
AccountId::from(ALICE).into(),
true,
minimum_asset_balance
));
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
local_asset_id.into(),
AccountId::from(ALICE).into(),
minimum_asset_balance
));
// check after
assert_eq!(
Assets::balance(local_asset_id, AccountId::from(ALICE)),
minimum_asset_balance
);
assert_eq!(Balances::free_balance(AccountId::from(ALICE)), some_currency);
let result = Runtime::query_account_balances(AccountId::from(ALICE)).unwrap();
assert_eq!(result.len(), 2);
// check currency
assert!(result.iter().any(|asset| asset.eq(
&assets_common::fungible_conversion::convert_balance::<KsmLocation, Balance>(
some_currency
)
.unwrap()
)));
// check trusted asset
assert!(result.iter().any(|asset| asset.eq(&(
AssetIdForTrustBackedAssetsConvert::reverse_ref(local_asset_id).unwrap(),
minimum_asset_balance
)
.into())));
});
}
#[test]
fn receive_teleported_asset_works() {
ExtBuilder::<Runtime>::default()
@@ -47,6 +47,7 @@ sp-version = { git = "https://github.com/paritytech/substrate", default-features
# Polkadot
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true }
polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
@@ -68,7 +69,7 @@ cumulus-primitives-utility = { path = "../../../../primitives/utility", default-
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
parachain-info = { path = "../../../pallets/parachain-info", default-features = false }
parachains-common = { path = "../../../common", default-features = false }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true }
assets-common = { path = "../common", default-features = false }
[dev-dependencies]
hex-literal = "0.3.4"
@@ -176,4 +177,5 @@ std = [
"pallet-collator-selection/std",
"parachain-info/std",
"parachains-common/std",
"assets-common/std",
]
@@ -93,7 +93,9 @@ use parachains_common::{
Signature, StatemintAuraId as AuraId, AVERAGE_ON_INITIALIZE_RATIO, HOURS, MAXIMUM_BLOCK_WEIGHT,
NORMAL_DISPATCH_RATIO, SLOT_DURATION,
};
use xcm_config::{DotLocation, XcmConfig, XcmOriginToTransactDispatchOrigin};
use xcm_config::{
DotLocation, TrustBackedAssetsConvertedConcreteId, XcmConfig, XcmOriginToTransactDispatchOrigin,
};
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
@@ -828,6 +830,34 @@ impl_runtime_apis! {
}
}
impl assets_common::runtime_api::FungiblesApi<
Block,
AccountId,
> for Runtime
{
fn query_account_balances(account: AccountId) -> Result<Vec<xcm::latest::MultiAsset>, assets_common::runtime_api::FungiblesAccessError> {
use assets_common::fungible_conversion::{convert, convert_balance};
Ok([
// collect pallet_balance
{
let balance = Balances::free_balance(account.clone());
if balance > 0 {
vec![convert_balance::<DotLocation, Balance>(balance)?]
} else {
vec![]
}
},
// collect pallet_assets (TrustBackedAssets)
convert::<_, _, _, _, TrustBackedAssetsConvertedConcreteId>(
Assets::account_balances(account)
.iter()
.filter(|(_, balance)| balance > &0)
)?,
// collect ... e.g. pallet_assets ForeignAssets
].concat())
}
}
impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
fn collect_collation_info(header: &<Block as BlockT>::Header) -> cumulus_primitives_core::CollationInfo {
ParachainSystem::collect_collation_info(header)
@@ -14,9 +14,9 @@
// limitations under the License.
use super::{
AccountId, AllPalletsWithSystem, AssetIdForTrustBackedAssets, Assets, Authorship, Balance,
Balances, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent,
RuntimeOrigin, TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ParachainInfo,
ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
};
use frame_support::{
match_types, parameter_types,
@@ -34,17 +34,13 @@ use sp_runtime::traits::ConvertInto;
use xcm::latest::prelude::*;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex,
ConvertedConcreteId, CurrencyAdapter, EnsureXcmOrigin, FungiblesAdapter, IsConcrete, LocalMint,
NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, WeightInfoBounds,
WithComputedOrigin,
};
use xcm_executor::{
traits::{JustTry, WithOriginFilter},
XcmExecutor,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, EnsureXcmOrigin,
FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, ParentAsSuperuser, ParentIsPreset,
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
UsingComponents, WeightInfoBounds, WithComputedOrigin,
};
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
parameter_types! {
pub const DotLocation: MultiLocation = MultiLocation::parent();
@@ -84,21 +80,16 @@ pub type CurrencyTransactor = CurrencyAdapter<
(),
>;
/// `AssetId/Balancer` converter for `TrustBackedAssets``
pub type TrustBackedAssetsConvertedConcreteId =
assets_common::TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance>;
/// Means for transacting assets besides the native currency on this chain.
pub type FungiblesTransactor = FungiblesAdapter<
// Use this fungibles implementation:
Assets,
// Use this currency when it is a fungible asset matching the given location or name:
ConvertedConcreteId<
AssetIdForTrustBackedAssets,
Balance,
AsPrefixedGeneralIndex<
TrustBackedAssetsPalletLocation,
AssetIdForTrustBackedAssets,
JustTry,
>,
JustTry,
>,
TrustBackedAssetsConvertedConcreteId,
// 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):
@@ -302,16 +293,7 @@ impl xcm_executor::Config for XcmConfig {
cumulus_primitives_utility::TakeFirstAssetTrader<
AccountId,
AssetFeeAsExistentialDepositMultiplierFeeCharger,
ConvertedConcreteId<
AssetIdForTrustBackedAssets,
Balance,
AsPrefixedGeneralIndex<
TrustBackedAssetsPalletLocation,
AssetIdForTrustBackedAssets,
JustTry,
>,
JustTry,
>,
TrustBackedAssetsConvertedConcreteId,
Assets,
cumulus_primitives_utility::XcmFeesTo32ByteAccount<
FungiblesTransactor,
@@ -3,20 +3,27 @@ use codec::Encode;
use cumulus_primitives_utility::ChargeWeightInFungibles;
use frame_support::{
assert_noop, assert_ok, sp_io,
traits::PalletInfo,
weights::{Weight, WeightToFee as WeightToFeeT},
};
use parachains_common::{AccountId, StatemintAuraId as AuraId};
use statemint_runtime::xcm_config::AssetFeeAsExistentialDepositMultiplierFeeCharger;
use parachains_common::{AccountId, Balance, StatemintAuraId as AuraId};
use statemint_runtime::xcm_config::{
AssetFeeAsExistentialDepositMultiplierFeeCharger, DotLocation, TrustBackedAssetsPalletLocation,
};
pub use statemint_runtime::{
constants::fee::WeightToFee, xcm_config::XcmConfig, Assets, Balances, ExistentialDeposit,
ReservedDmpWeight, Runtime, SessionKeys, System,
};
use xcm::latest::prelude::*;
use xcm_executor::{traits::WeightTrader, XcmExecutor};
use xcm_executor::{
traits::{Convert, WeightTrader},
XcmExecutor,
};
pub const ALICE: [u8; 32] = [1u8; 32];
type AssetIdForTrustBackedAssetsConvert =
assets_common::AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>;
#[test]
fn test_asset_xcm_trader() {
ExtBuilder::<Runtime>::default()
@@ -48,16 +55,8 @@ fn test_asset_xcm_trader() {
));
// get asset id as multilocation
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(local_asset_id.into()),
),
);
let asset_multilocation =
AssetIdForTrustBackedAssetsConvert::reverse_ref(local_asset_id).unwrap();
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
@@ -98,12 +97,15 @@ fn test_asset_xcm_trader() {
// Make sure author(Alice) has received the amount
assert_eq!(
Assets::balance(1, AccountId::from(ALICE)),
Assets::balance(local_asset_id, AccountId::from(ALICE)),
minimum_asset_balance + asset_amount_needed
);
// We also need to ensure the total supply increased
assert_eq!(Assets::total_supply(1), minimum_asset_balance + asset_amount_needed);
assert_eq!(
Assets::total_supply(local_asset_id),
minimum_asset_balance + asset_amount_needed
);
});
}
@@ -147,16 +149,7 @@ fn test_asset_xcm_trader_with_refund() {
// bit more of weight
let bought = Weight::from_ref_time(400_000_000_000u64);
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(1),
),
);
let asset_multilocation = AssetIdForTrustBackedAssetsConvert::reverse_ref(1).unwrap();
// lets calculate amount needed
let amount_bought = WeightToFee::weight_to_fee(&bought);
@@ -228,16 +221,7 @@ fn test_asset_xcm_trader_refund_not_possible_since_amount_less_than_ed() {
// bit more of weight
let bought = Weight::from_ref_time(50_000_000_000u64);
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(1),
),
);
let asset_multilocation = AssetIdForTrustBackedAssetsConvert::reverse_ref(1).unwrap();
let amount_bought = WeightToFee::weight_to_fee(&bought);
@@ -288,16 +272,7 @@ fn test_that_buying_ed_refund_does_not_refund() {
// We are gonna buy ED
let bought = Weight::from_ref_time(ExistentialDeposit::get().try_into().unwrap());
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(1),
),
);
let asset_multilocation = AssetIdForTrustBackedAssetsConvert::reverse_ref(1).unwrap();
let amount_bought = WeightToFee::weight_to_fee(&bought);
@@ -375,16 +350,7 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
// lets calculate amount needed
let asset_amount_needed = WeightToFee::weight_to_fee(&bought);
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(1),
),
);
let asset_multilocation = AssetIdForTrustBackedAssetsConvert::reverse_ref(1).unwrap();
let asset: MultiAsset = (asset_multilocation, asset_amount_needed).into();
@@ -402,6 +368,75 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
});
}
#[test]
fn test_assets_balances_api_works() {
use assets_common::runtime_api::runtime_decl_for_FungiblesApi::FungiblesApi;
ExtBuilder::<Runtime>::default()
.with_collators(vec![AccountId::from(ALICE)])
.with_session_keys(vec![(
AccountId::from(ALICE),
AccountId::from(ALICE),
SessionKeys { aura: AuraId::from(sp_core::ed25519::Public::from_raw(ALICE)) },
)])
.build()
.execute_with(|| {
let local_asset_id = 1;
// check before
assert_eq!(Assets::balance(local_asset_id, AccountId::from(ALICE)), 0);
assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 0);
assert!(Runtime::query_account_balances(AccountId::from(ALICE)).unwrap().is_empty());
// Drip some balance
use frame_support::traits::fungible::Mutate;
let some_currency = ExistentialDeposit::get();
Balances::mint_into(&AccountId::from(ALICE), some_currency).unwrap();
// We need root origin to create a sufficient asset
let minimum_asset_balance = 3333333_u128;
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
local_asset_id.into(),
AccountId::from(ALICE).into(),
true,
minimum_asset_balance
));
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
local_asset_id.into(),
AccountId::from(ALICE).into(),
minimum_asset_balance
));
// check after
assert_eq!(
Assets::balance(local_asset_id, AccountId::from(ALICE)),
minimum_asset_balance
);
assert_eq!(Balances::free_balance(AccountId::from(ALICE)), some_currency);
let result = Runtime::query_account_balances(AccountId::from(ALICE)).unwrap();
assert_eq!(result.len(), 2);
// check currency
assert!(result.iter().any(|asset| asset.eq(
&assets_common::fungible_conversion::convert_balance::<DotLocation, Balance>(
some_currency
)
.unwrap()
)));
// check trusted asset
assert!(result.iter().any(|asset| asset.eq(&(
AssetIdForTrustBackedAssetsConvert::reverse_ref(local_asset_id).unwrap(),
minimum_asset_balance
)
.into())));
});
}
#[test]
fn receive_teleported_asset_works() {
ExtBuilder::<Runtime>::default()
@@ -49,6 +49,7 @@ sp-version = { git = "https://github.com/paritytech/substrate", default-features
# Polkadot
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true }
polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
@@ -70,7 +71,7 @@ cumulus-primitives-utility = { path = "../../../../primitives/utility", default-
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
parachain-info = { path = "../../../pallets/parachain-info", default-features = false }
parachains-common = { path = "../../../common", default-features = false }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true }
assets-common = { path = "../common", default-features = false }
[dev-dependencies]
hex-literal = "0.3.4"
@@ -182,4 +183,5 @@ std = [
"pallet-collator-selection/std",
"parachain-info/std",
"parachains-common/std",
"assets-common/std",
]
@@ -68,7 +68,10 @@ use parachains_common::{
Index, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT,
NORMAL_DISPATCH_RATIO, SLOT_DURATION,
};
use xcm_config::{XcmConfig, XcmOriginToTransactDispatchOrigin};
use xcm_config::{
TrustBackedAssetsConvertedConcreteId, WestendLocation, XcmConfig,
XcmOriginToTransactDispatchOrigin,
};
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
@@ -890,6 +893,34 @@ impl_runtime_apis! {
}
}
impl assets_common::runtime_api::FungiblesApi<
Block,
AccountId,
> for Runtime
{
fn query_account_balances(account: AccountId) -> Result<Vec<xcm::latest::MultiAsset>, assets_common::runtime_api::FungiblesAccessError> {
use assets_common::fungible_conversion::{convert, convert_balance};
Ok([
// collect pallet_balance
{
let balance = Balances::free_balance(account.clone());
if balance > 0 {
vec![convert_balance::<WestendLocation, Balance>(balance)?]
} else {
vec![]
}
},
// collect pallet_assets (TrustBackedAssets)
convert::<_, _, _, _, TrustBackedAssetsConvertedConcreteId>(
Assets::account_balances(account)
.iter()
.filter(|(_, balance)| balance > &0)
)?,
// collect ... e.g. pallet_assets ForeignAssets
].concat())
}
}
impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
fn collect_collation_info(header: &<Block as BlockT>::Header) -> cumulus_primitives_core::CollationInfo {
ParachainSystem::collect_collation_info(header)
@@ -14,9 +14,9 @@
// limitations under the License.
use super::{
AccountId, AllPalletsWithSystem, AssetIdForTrustBackedAssets, Assets, Authorship, Balance,
Balances, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent,
RuntimeOrigin, TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ParachainInfo,
ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
};
use frame_support::{
match_types, parameter_types,
@@ -34,17 +34,13 @@ use sp_runtime::traits::ConvertInto;
use xcm::latest::prelude::*;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex,
ConvertedConcreteId, CurrencyAdapter, EnsureXcmOrigin, FungiblesAdapter, IsConcrete, LocalMint,
NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, WeightInfoBounds,
WithComputedOrigin,
};
use xcm_executor::{
traits::{JustTry, WithOriginFilter},
XcmExecutor,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, EnsureXcmOrigin,
FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, ParentAsSuperuser, ParentIsPreset,
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
UsingComponents, WeightInfoBounds, WithComputedOrigin,
};
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
parameter_types! {
pub const WestendLocation: MultiLocation = MultiLocation::parent();
@@ -84,21 +80,16 @@ pub type CurrencyTransactor = CurrencyAdapter<
(),
>;
/// `AssetId/Balancer` converter for `TrustBackedAssets`
pub type TrustBackedAssetsConvertedConcreteId =
assets_common::TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance>;
/// Means for transacting assets besides the native currency on this chain.
pub type FungiblesTransactor = FungiblesAdapter<
// Use this fungibles implementation:
Assets,
// Use this currency when it is a fungible asset matching the given location or name:
ConvertedConcreteId<
AssetIdForTrustBackedAssets,
Balance,
AsPrefixedGeneralIndex<
TrustBackedAssetsPalletLocation,
AssetIdForTrustBackedAssets,
JustTry,
>,
JustTry,
>,
TrustBackedAssetsConvertedConcreteId,
// 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):
@@ -297,16 +288,7 @@ impl xcm_executor::Config for XcmConfig {
cumulus_primitives_utility::TakeFirstAssetTrader<
AccountId,
AssetFeeAsExistentialDepositMultiplierFeeCharger,
ConvertedConcreteId<
AssetIdForTrustBackedAssets,
Balance,
AsPrefixedGeneralIndex<
TrustBackedAssetsPalletLocation,
AssetIdForTrustBackedAssets,
JustTry,
>,
JustTry,
>,
TrustBackedAssetsConvertedConcreteId,
Assets,
cumulus_primitives_utility::XcmFeesTo32ByteAccount<
FungiblesTransactor,
@@ -3,20 +3,29 @@ use codec::{DecodeLimit, Encode};
use cumulus_primitives_utility::ChargeWeightInFungibles;
use frame_support::{
assert_noop, assert_ok, sp_io,
traits::PalletInfo,
weights::{Weight, WeightToFee as WeightToFeeT},
};
use parachains_common::{AccountId, AuraId};
use parachains_common::{AccountId, AuraId, Balance};
pub use westmint_runtime::{
constants::fee::WeightToFee, xcm_config::XcmConfig, Assets, Balances, ExistentialDeposit,
ReservedDmpWeight, Runtime, SessionKeys, System,
constants::fee::WeightToFee,
xcm_config::{TrustBackedAssetsPalletLocation, XcmConfig},
Assets, Balances, ExistentialDeposit, ReservedDmpWeight, Runtime, SessionKeys, System,
};
use westmint_runtime::{
xcm_config::{AssetFeeAsExistentialDepositMultiplierFeeCharger, WestendLocation},
RuntimeCall,
};
use westmint_runtime::{xcm_config::AssetFeeAsExistentialDepositMultiplierFeeCharger, RuntimeCall};
use xcm::{latest::prelude::*, VersionedXcm, MAX_XCM_DECODE_DEPTH};
use xcm_executor::{traits::WeightTrader, XcmExecutor};
use xcm_executor::{
traits::{Convert, WeightTrader},
XcmExecutor,
};
pub const ALICE: [u8; 32] = [1u8; 32];
type AssetIdForTrustBackedAssetsConvert =
assets_common::AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>;
#[test]
fn test_asset_xcm_trader() {
ExtBuilder::<Runtime>::default()
@@ -48,16 +57,8 @@ fn test_asset_xcm_trader() {
));
// get asset id as multilocation
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(local_asset_id.into()),
),
);
let asset_multilocation =
AssetIdForTrustBackedAssetsConvert::reverse_ref(local_asset_id).unwrap();
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
@@ -95,12 +96,15 @@ fn test_asset_xcm_trader() {
// Make sure author(Alice) has received the amount
assert_eq!(
Assets::balance(1, AccountId::from(ALICE)),
Assets::balance(local_asset_id, AccountId::from(ALICE)),
minimum_asset_balance + asset_amount_needed
);
// We also need to ensure the total supply increased
assert_eq!(Assets::total_supply(1), minimum_asset_balance + asset_amount_needed);
assert_eq!(
Assets::total_supply(local_asset_id),
minimum_asset_balance + asset_amount_needed
);
});
}
@@ -140,16 +144,7 @@ fn test_asset_xcm_trader_with_refund() {
// We are going to buy 4e9 weight
let bought = Weight::from_ref_time(4_000_000_000u64);
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(1),
),
);
let asset_multilocation = AssetIdForTrustBackedAssetsConvert::reverse_ref(1).unwrap();
// lets calculate amount needed
let amount_bought = WeightToFee::weight_to_fee(&bought);
@@ -218,16 +213,7 @@ fn test_asset_xcm_trader_refund_not_possible_since_amount_less_than_ed() {
// We are going to buy 5e9 weight
let bought = Weight::from_ref_time(500_000_000u64);
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(1),
),
);
let asset_multilocation = AssetIdForTrustBackedAssetsConvert::reverse_ref(1).unwrap();
let amount_bought = WeightToFee::weight_to_fee(&bought);
@@ -277,16 +263,7 @@ fn test_that_buying_ed_refund_does_not_refund() {
let bought = Weight::from_ref_time(500_000_000u64);
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(1),
),
);
let asset_multilocation = AssetIdForTrustBackedAssetsConvert::reverse_ref(1).unwrap();
let amount_bought = WeightToFee::weight_to_fee(&bought);
@@ -361,16 +338,7 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
// lets calculate amount needed
let asset_amount_needed = WeightToFee::weight_to_fee(&bought);
let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(1),
),
);
let asset_multilocation = AssetIdForTrustBackedAssetsConvert::reverse_ref(1).unwrap();
let asset: MultiAsset = (asset_multilocation, asset_amount_needed).into();
@@ -388,6 +356,75 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
});
}
#[test]
fn test_assets_balances_api_works() {
use assets_common::runtime_api::runtime_decl_for_FungiblesApi::FungiblesApi;
ExtBuilder::<Runtime>::default()
.with_collators(vec![AccountId::from(ALICE)])
.with_session_keys(vec![(
AccountId::from(ALICE),
AccountId::from(ALICE),
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) },
)])
.build()
.execute_with(|| {
let local_asset_id = 1;
// check before
assert_eq!(Assets::balance(local_asset_id, AccountId::from(ALICE)), 0);
assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 0);
assert!(Runtime::query_account_balances(AccountId::from(ALICE)).unwrap().is_empty());
// Drip some balance
use frame_support::traits::fungible::Mutate;
let some_currency = ExistentialDeposit::get();
Balances::mint_into(&AccountId::from(ALICE), some_currency).unwrap();
// We need root origin to create a sufficient asset
let minimum_asset_balance = 3333333_u128;
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
local_asset_id.into(),
AccountId::from(ALICE).into(),
true,
minimum_asset_balance
));
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
local_asset_id.into(),
AccountId::from(ALICE).into(),
minimum_asset_balance
));
// check after
assert_eq!(
Assets::balance(local_asset_id, AccountId::from(ALICE)),
minimum_asset_balance
);
assert_eq!(Balances::free_balance(AccountId::from(ALICE)), some_currency);
let result = Runtime::query_account_balances(AccountId::from(ALICE)).unwrap();
assert_eq!(result.len(), 2);
// check currency
assert!(result.iter().any(|asset| asset.eq(
&assets_common::fungible_conversion::convert_balance::<WestendLocation, Balance>(
some_currency
)
.unwrap()
)));
// check trusted asset
assert!(result.iter().any(|asset| asset.eq(&(
AssetIdForTrustBackedAssetsConvert::reverse_ref(local_asset_id).unwrap(),
minimum_asset_balance
)
.into())));
});
}
#[test]
fn receive_teleported_asset_works() {
ExtBuilder::<Runtime>::default()