Skip to content
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
4 changes: 0 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Copyright (C) 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.

use crate::{
create_pool_with_wnd_on,
imports::{
asset_hub_westend_runtime::{ExistentialDeposit, Runtime},
*,
},
};
use asset_hub_westend_runtime::{
xcm_config::WestendLocation, Balances, ForeignAssets, PolkadotXcm, RuntimeOrigin,
};
use emulated_integration_tests_common::{accounts::ALICE, xcm_emulator::TestExt};
use frame_support::{
assert_err_ignore_postinfo, assert_ok,
traits::fungible::{Inspect, Mutate},
};
use parachains_common::{AccountId, Balance};
use std::convert::Into;
use xcm::latest::{Assets, Location, Xcm};

const UNITS: Balance = 1_000_000_000;

#[test]
fn exchange_asset_success() {
test_exchange_asset(true, 500 * UNITS, 665 * UNITS, true);
}

#[test]
fn exchange_asset_insufficient_liquidity() {
test_exchange_asset(true, 1_000 * UNITS, 2_000 * UNITS, false);
}

#[test]
fn exchange_asset_insufficient_balance() {
test_exchange_asset(true, 5_000 * UNITS, 1_665 * UNITS, false);
}

#[test]
fn exchange_asset_pool_not_created() {
test_exchange_asset(false, 500 * UNITS, 665 * UNITS, false);
}

fn test_exchange_asset(
create_pool: bool,
give_amount: Balance,
want_amount: Balance,
should_succeed: bool,
) {
let alice: AccountId = Westend::account_id_of(ALICE);
let native_asset_location = WestendLocation::get();
let native_asset_id = AssetId(native_asset_location.clone());
let origin = RuntimeOrigin::signed(alice.clone());
let asset_location = Location::new(1, [Parachain(2001)]);
let asset_id = AssetId(asset_location.clone());

// Setup initial state
AssetHubWestend::execute_with(|| {
assert_ok!(<Balances as Mutate<_>>::mint_into(
&alice,
ExistentialDeposit::get() + (1_000 * UNITS)
));

assert_ok!(ForeignAssets::force_create(
RuntimeOrigin::root(),
asset_location.clone().into(),
alice.clone().into(),
true,
1
));
});

if create_pool {
create_pool_with_wnd_on!(AssetHubWestend, asset_location.clone(), true, alice.clone());
}

// Execute and verify swap
AssetHubWestend::execute_with(|| {
let foreign_balance_before = ForeignAssets::balance(asset_location.clone(), &alice);
let wnd_balance_before = Balances::total_balance(&alice);

let give: Assets = (native_asset_id, give_amount).into();
let want: Assets = (asset_id, want_amount).into();
let xcm = Xcm(vec![
WithdrawAsset(give.clone().into()),
ExchangeAsset { give: give.into(), want: want.into(), maximal: true },
DepositAsset { assets: Wild(All), beneficiary: alice.clone().into() },
]);

let result = PolkadotXcm::execute(origin, bx!(xcm::VersionedXcm::from(xcm)), Weight::MAX);

let foreign_balance_after = ForeignAssets::balance(asset_location, &alice);
let wnd_balance_after = Balances::total_balance(&alice);

if should_succeed {
assert_ok!(result);
assert!(
foreign_balance_after >= foreign_balance_before + want_amount,
"Expected foreign balance to increase by at least {want_amount} units, got {foreign_balance_after} from {foreign_balance_before}"
);
assert_eq!(
wnd_balance_after, wnd_balance_before - give_amount,
"Expected WND balance to decrease by {give_amount} units, got {wnd_balance_after} from {wnd_balance_before}"
);
} else {
assert_err_ignore_postinfo!(
result,
pallet_xcm::Error::<Runtime>::LocalExecutionIncomplete
);
assert_eq!(
foreign_balance_after, foreign_balance_before,
"Foreign balance changed unexpectedly: got {foreign_balance_after}, expected {foreign_balance_before}"
);
assert_eq!(
wnd_balance_after, wnd_balance_before,
"WND balance changed unexpectedly: got {wnd_balance_after}, expected {wnd_balance_before}"
);
}
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// limitations under the License.

mod claim_assets;
mod exchange_asset;
mod fellowship_treasury;
mod hybrid_transfers;
mod reserve_transfer;
Expand All @@ -23,3 +24,67 @@ mod swap;
mod teleport;
mod treasury;
mod xcm_fee_estimation;

#[macro_export]
macro_rules! create_pool_with_wnd_on {
( $chain:ident, $asset_id:expr, $is_foreign:expr, $asset_owner:expr ) => {
emulated_integration_tests_common::impls::paste::paste! {
<$chain>::execute_with(|| {
type RuntimeEvent = <$chain as Chain>::RuntimeEvent;
let owner = $asset_owner;
let signed_owner = <$chain as Chain>::RuntimeOrigin::signed(owner.clone());
let wnd_location: Location = Parent.into();
if $is_foreign {
assert_ok!(<$chain as [<$chain Pallet>]>::ForeignAssets::mint(
signed_owner.clone(),
$asset_id.clone().into(),
owner.clone().into(),
10_000_000_000_000, // For it to have more than enough.
));
} else {
let asset_id = match $asset_id.interior.last() {
Some(GeneralIndex(id)) => *id as u32,
_ => unreachable!(),
};
assert_ok!(<$chain as [<$chain Pallet>]>::Assets::mint(
signed_owner.clone(),
asset_id.into(),
owner.clone().into(),
10_000_000_000_000, // For it to have more than enough.
));
}

assert_ok!(<$chain as [<$chain Pallet>]>::AssetConversion::create_pool(
signed_owner.clone(),
Box::new(wnd_location.clone()),
Box::new($asset_id.clone()),
));

assert_expected_events!(
$chain,
vec![
RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {},
]
);

assert_ok!(<$chain as [<$chain Pallet>]>::AssetConversion::add_liquidity(
signed_owner,
Box::new(wnd_location),
Box::new($asset_id),
1_000_000_000_000,
2_000_000_000_000, // $asset_id is worth half of wnd
0,
0,
owner.into()
));

assert_expected_events!(
$chain,
vec![
RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {},
]
);
});
}
};
}
51 changes: 50 additions & 1 deletion cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1800,7 +1800,56 @@ impl_runtime_apis! {
}

fn worst_case_asset_exchange() -> Result<(XcmAssets, XcmAssets), BenchmarkError> {
Err(BenchmarkError::Skip)
use frame_support::assert_ok;

let native_asset_location = WestendLocation::get();
let native_asset_id = AssetId(native_asset_location.clone());
let (account, _) = pallet_xcm_benchmarks::account_and_location::<Runtime>(1);
let origin = RuntimeOrigin::signed(account.clone());
let asset_location = Location::new(1, [Parachain(2001)]);
let asset_id = AssetId(asset_location.clone());

assert_ok!(<Balances as fungible::Mutate<_>>::mint_into(
&account,
ExistentialDeposit::get() + (1_000 * UNITS)
));

assert_ok!(ForeignAssets::force_create(
RuntimeOrigin::root(),
asset_location.clone().into(),
account.clone().into(),
true,
1,
));

assert_ok!(ForeignAssets::mint(
origin.clone(),
asset_location.clone().into(),
account.clone().into(),
3_000 * UNITS,
));

assert_ok!(AssetConversion::create_pool(
origin.clone(),
native_asset_location.clone().into(),
asset_location.clone().into(),
));

assert_ok!(AssetConversion::add_liquidity(
origin,
native_asset_location.into(),
asset_location.into(),
1_000 * UNITS,
2_000 * UNITS,
1,
1,
account.into(),
));

let give_assets: XcmAssets = (native_asset_id, 500 * UNITS).into();
let receive_assets: XcmAssets = (asset_id, 660 * UNITS).into();

Ok((give_assets, receive_assets))
}

fn universal_alias() -> Result<(Location, Junction), BenchmarkError> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,11 @@ impl<Call> XcmWeightInfo<Call> for AssetHubWestendXcmWeight<Call> {
fn deposit_reserve_asset(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
assets.weigh_assets(XcmFungibleWeight::<Runtime>::deposit_reserve_asset())
}
fn exchange_asset(_give: &AssetFilter, _receive: &Assets, _maximal: &bool) -> Weight {
Weight::MAX
fn exchange_asset(give: &AssetFilter, receive: &Assets, _maximal: &bool) -> Weight {
let base_weight = XcmGeneric::<Runtime>::exchange_asset();
let give_weight = give.weigh_assets(base_weight);
let receive_weight = receive.weigh_assets(base_weight);
give_weight.max(receive_weight)
}
fn initiate_reserve_withdraw(
assets: &AssetFilter,
Expand Down
Loading
Loading