Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
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
2 changes: 1 addition & 1 deletion parachains/common/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl ShouldExecute for DenyReserveTransferToRelayChain {
message.0.iter().any(|inst| matches!(inst, ReserveAssetDeposited { .. }))
{
log::warn!(
target: "xcm::barrier",
target: "xcm::barriers",
Comment thread
KiChjang marked this conversation as resolved.
"Unexpected ReserveAssetDeposited from the Relay Chain",
);
}
Expand Down
12 changes: 7 additions & 5 deletions parachains/runtimes/assets/statemine/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ pub type Barrier = DenyThenTry<
),
>;

pub type AssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentialDepositMultiplier<
Runtime,
WeightToFee,
pallet_assets::BalanceToAssetBalance<Balances, Runtime, ConvertInto>,
>;

pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
type RuntimeCall = RuntimeCall;
Expand All @@ -179,11 +185,7 @@ impl xcm_executor::Config for XcmConfig {
UsingComponents<WeightToFee, KsmLocation, AccountId, Balances, ToStakingPot<Runtime>>,
cumulus_primitives_utility::TakeFirstAssetTrader<
AccountId,
AssetFeeAsExistentialDepositMultiplier<
Runtime,
WeightToFee,
pallet_assets::BalanceToAssetBalance<Balances, Runtime, ConvertInto>,
>,
AssetFeeAsExistentialDepositMultiplierFeeCharger,
ConvertedConcreteAssetId<
AssetId,
Balance,
Expand Down
131 changes: 109 additions & 22 deletions parachains/runtimes/assets/statemine/tests/tests.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
use asset_test_utils::{ExtBuilder, RuntimeHelper};
use cumulus_primitives_utility::ChargeWeightInFungibles;
use frame_support::{
assert_noop, assert_ok,
traits::PalletInfo,
weights::{Weight, WeightToFee as WeightToFeeT},
};
use parachains_common::{AccountId, AuraId};
use statemine_runtime::xcm_config::AssetFeeAsExistentialDepositMultiplierFeeCharger;
pub use statemine_runtime::{
constants::fee::WeightToFee, xcm_config::XcmConfig, Assets, Balances, ExistentialDeposit,
Runtime, SessionKeys, System,
};
use xcm::latest::prelude::*;
use xcm_executor::traits::WeightTrader;

pub const ALICE: [u8; 32] = [1u8; 32];

#[test]
Expand All @@ -25,61 +28,78 @@ fn test_asset_xcm_trader() {
.build()
.execute_with(|| {
// We need root origin to create a sufficient asset
// We set existential deposit to be identical to the one for Balances first
let minimum_asset_balance = 3333333_u128;
let local_asset_id = 1;
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
1,
local_asset_id,
AccountId::from(ALICE).into(),
true,
ExistentialDeposit::get()
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)),
1,
local_asset_id,
AccountId::from(ALICE).into(),
ExistentialDeposit::get()
minimum_asset_balance
));

let mut trader = <XcmConfig as xcm_executor::Config>::Trader::new();

// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));

// We are going to buy 4e9 weight
let bought = 4_000_000_000u64;

// lets calculate amount needed
let amount_needed = WeightToFee::weight_to_fee(&Weight::from_ref_time(bought));

// 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(1),
GeneralIndex(local_asset_id.into()),
),
);

let asset: MultiAsset = (asset_multilocation, amount_needed).into();
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));

// Make sure buy_weight does not return an error
assert_ok!(trader.buy_weight(bought, asset.into()));
// We are going to buy 4e9 weight
let bought = 4_000_000_000u64;

// Lets calculate amount needed
let asset_amount_needed =
AssetFeeAsExistentialDepositMultiplierFeeCharger::charge_weight_in_fungibles(
local_asset_id,
Weight::from_ref_time(bought),
)
.expect("failed to compute");

// Lets pay with: asset_amount_needed + asset_amount_extra
let asset_amount_extra = 100_u128;
let asset: MultiAsset =
(asset_multilocation.clone(), asset_amount_needed + asset_amount_extra).into();

let mut trader = <XcmConfig as xcm_executor::Config>::Trader::new();

// Lets buy_weight and make sure buy_weight does not return an error
match trader.buy_weight(bought, asset.into()) {
Ok(unused_assets) => {
// Check whether a correct amount of unused assets is returned
assert_ok!(unused_assets
.ensure_contains(&(asset_multilocation, asset_amount_extra).into()));
},
Err(e) => assert!(false, "Expected Ok(_). Got {:#?}", e),
}

// Drop trader
drop(trader);

// Make sure author(Alice) has received the amount
assert_eq!(
Assets::balance(1, AccountId::from(ALICE)),
ExistentialDeposit::get() + amount_needed
minimum_asset_balance + asset_amount_needed
);

// We also need to ensure the total supply increased
assert_eq!(Assets::total_supply(1), ExistentialDeposit::get() + amount_needed);
assert_eq!(Assets::total_supply(1), minimum_asset_balance + asset_amount_needed);
});
}

Expand Down Expand Up @@ -302,3 +322,70 @@ fn test_that_buying_ed_refund_does_not_refund() {
assert_eq!(Assets::total_supply(1), ExistentialDeposit::get());
});
}

#[test]
fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
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(|| {
// Create a non-sufficient asset with specific existential deposit
let minimum_asset_balance = 1_000_000_u128;
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
1,
Comment thread
bkontur marked this conversation as resolved.
AccountId::from(ALICE).into(),
false,
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)),
1,
AccountId::from(ALICE).into(),
minimum_asset_balance
));

let mut trader = <XcmConfig as xcm_executor::Config>::Trader::new();

// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));

// We are going to buy 4e9 weight
let bought = 4_000_000_000u64;

// lets calculate amount needed
let asset_amount_needed = WeightToFee::weight_to_fee(&Weight::from_ref_time(bought));

let asset_multilocation = MultiLocation::new(
0,
X2(
PalletInstance(
<Runtime as frame_system::Config>::PalletInfo::index::<Assets>().unwrap()
as u8,
),
GeneralIndex(1),
),
);

let asset: MultiAsset = (asset_multilocation, asset_amount_needed).into();

// Make sure again buy_weight does return an error
assert_noop!(trader.buy_weight(bought, asset.into()), XcmError::TooExpensive);

// Drop trader
drop(trader);

// Make sure author(Alice) has NOT received the amount
assert_eq!(Assets::balance(1, AccountId::from(ALICE)), minimum_asset_balance);

// We also need to ensure the total supply NOT increased
assert_eq!(Assets::total_supply(1), minimum_asset_balance);
});
}
32 changes: 29 additions & 3 deletions parachains/runtimes/assets/statemint/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ use frame_support::{
use pallet_xcm::XcmPassthrough;
use parachains_common::{
impls::ToStakingPot,
xcm_config::{DenyReserveTransferToRelayChain, DenyThenTry},
xcm_config::{
AssetFeeAsExistentialDepositMultiplier, DenyReserveTransferToRelayChain, DenyThenTry,
},
};
use polkadot_parachain::primitives::Sibling;
use sp_runtime::traits::ConvertInto;
use xcm::latest::prelude::*;
use xcm_builder::{
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
Expand Down Expand Up @@ -154,6 +157,12 @@ pub type Barrier = DenyThenTry<
),
>;

pub type AssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentialDepositMultiplier<
Runtime,
WeightToFee,
pallet_assets::BalanceToAssetBalance<Balances, Runtime, ConvertInto>,
>;

pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
type RuntimeCall = RuntimeCall;
Expand All @@ -172,8 +181,25 @@ impl xcm_executor::Config for XcmConfig {
RuntimeCall,
MaxInstructions,
>;
type Trader =
UsingComponents<WeightToFee, DotLocation, AccountId, Balances, ToStakingPot<Runtime>>;
type Trader = (
UsingComponents<WeightToFee, DotLocation, AccountId, Balances, ToStakingPot<Runtime>>,
cumulus_primitives_utility::TakeFirstAssetTrader<
AccountId,
AssetFeeAsExistentialDepositMultiplierFeeCharger,
ConvertedConcreteAssetId<
AssetId,
Balance,
AsPrefixedGeneralIndex<AssetsPalletLocation, AssetId, JustTry>,
JustTry,
>,
Assets,
cumulus_primitives_utility::XcmFeesTo32ByteAccount<
FungiblesTransactor,
AccountId,
XcmAssetFeesReceiver,
>,
>,
);
type ResponseHandler = PolkadotXcm;
type AssetTrap = PolkadotXcm;
type AssetClaims = PolkadotXcm;
Expand Down
Loading