feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
+111
@@ -0,0 +1,111 @@
|
||||
// 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.
|
||||
|
||||
#[cfg(test)]
|
||||
mod imports {
|
||||
pub(crate) use codec::Encode;
|
||||
|
||||
// Bizinikiwi
|
||||
pub(crate) use pezframe_support::{
|
||||
assert_err, assert_ok,
|
||||
pezpallet_prelude::Weight,
|
||||
pezsp_runtime::{DispatchError, DispatchResult, ModuleError},
|
||||
traits::fungibles::Inspect,
|
||||
};
|
||||
|
||||
// Pezkuwi
|
||||
pub(crate) use xcm::{
|
||||
latest::{PEZKUWICHAIN_GENESIS_HASH, ZAGROS_GENESIS_HASH},
|
||||
prelude::{AccountId32 as AccountId32Junction, *},
|
||||
};
|
||||
pub(crate) use xcm_executor::traits::TransferType;
|
||||
|
||||
// Pezcumulus
|
||||
pub(crate) use asset_test_utils::xcm_helpers;
|
||||
pub(crate) use emulated_integration_tests_common::{
|
||||
accounts::DUMMY_EMPTY,
|
||||
test_relay_is_trusted_teleporter, test_teyrchain_is_trusted_teleporter,
|
||||
test_teyrchain_is_trusted_teleporter_for_relay,
|
||||
test_xcm_fee_querying_apis_work_for_asset_hub,
|
||||
xcm_emulator::{
|
||||
assert_expected_events, bx, Chain, RelayChain as Relay, Test, TestArgs, TestContext,
|
||||
TestExt, Teyrchain as Para,
|
||||
},
|
||||
xcm_helpers::{
|
||||
fee_asset, get_amount_from_versioned_assets, non_fee_asset, xcm_transact_paid_execution,
|
||||
},
|
||||
PenpalATeleportableAssetLocation, ASSETS_PALLET_ID, RESERVABLE_ASSET_ID, XCM_V3,
|
||||
};
|
||||
pub(crate) use pezkuwichain_system_emulated_network::{
|
||||
asset_hub_pezkuwichain_emulated_chain::{
|
||||
asset_hub_pezkuwichain_runtime::{
|
||||
self,
|
||||
xcm_config::{
|
||||
self as ahr_xcm_config, TokenLocation as RelayLocation, TreasuryAccount,
|
||||
XcmConfig as AssetHubPezkuwichainXcmConfig,
|
||||
},
|
||||
AssetConversionOrigin as AssetHubPezkuwichainAssetConversionOrigin,
|
||||
ExistentialDeposit as AssetHubPezkuwichainExistentialDeposit,
|
||||
},
|
||||
genesis::{AssetHubPezkuwichainAssetOwner, ED as ASSET_HUB_PEZKUWICHAIN_ED},
|
||||
AssetHubPezkuwichainParaPallet as AssetHubPezkuwichainPallet,
|
||||
},
|
||||
penpal_emulated_chain::{
|
||||
penpal_runtime::xcm_config::{
|
||||
CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub,
|
||||
LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub,
|
||||
LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub,
|
||||
UsdtFromAssetHub as PenpalUsdtFromAssetHub,
|
||||
},
|
||||
PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner,
|
||||
PenpalBParaPallet as PenpalBPallet, ED as PENPAL_ED,
|
||||
},
|
||||
pezkuwichain_emulated_chain::{
|
||||
genesis::ED as PEZKUWICHAIN_ED,
|
||||
pezkuwichain_runtime::{
|
||||
governance as pezkuwichain_governance,
|
||||
governance::pezpallet_custom_origins::Origin::Treasurer,
|
||||
xcm_config::UniversalLocation as PezkuwichainUniversalLocation, Dmp,
|
||||
OriginCaller as PezkuwichainOriginCaller,
|
||||
},
|
||||
PezkuwichainRelayPallet as PezkuwichainPallet,
|
||||
},
|
||||
AssetHubPezkuwichainPara as AssetHubPezkuwichain,
|
||||
AssetHubPezkuwichainParaReceiver as AssetHubPezkuwichainReceiver,
|
||||
AssetHubPezkuwichainParaSender as AssetHubPezkuwichainSender,
|
||||
BridgeHubPezkuwichainPara as BridgeHubPezkuwichain,
|
||||
BridgeHubPezkuwichainParaReceiver as BridgeHubPezkuwichainReceiver, PenpalAPara as PenpalA,
|
||||
PenpalAParaReceiver as PenpalAReceiver, PenpalAParaSender as PenpalASender,
|
||||
PenpalBPara as PenpalB, PenpalBParaReceiver as PenpalBReceiver,
|
||||
PezkuwichainRelay as Pezkuwichain, PezkuwichainRelayReceiver as PezkuwichainReceiver,
|
||||
PezkuwichainRelaySender as PezkuwichainSender,
|
||||
};
|
||||
pub(crate) use teyrchains_common::Balance;
|
||||
|
||||
pub(crate) const ASSET_ID: u32 = 3;
|
||||
pub(crate) const ASSET_MIN_BALANCE: u128 = 1000;
|
||||
|
||||
pub(crate) type RelayToParaTest = Test<Pezkuwichain, PenpalA>;
|
||||
pub(crate) type ParaToRelayTest = Test<PenpalA, Pezkuwichain>;
|
||||
pub(crate) type SystemParaToRelayTest = Test<AssetHubPezkuwichain, Pezkuwichain>;
|
||||
pub(crate) type SystemParaToParaTest = Test<AssetHubPezkuwichain, PenpalA>;
|
||||
pub(crate) type ParaToSystemParaTest = Test<PenpalA, AssetHubPezkuwichain>;
|
||||
pub(crate) type ParaToParaThroughRelayTest = Test<PenpalA, PenpalB, Pezkuwichain>;
|
||||
pub(crate) type ParaToParaThroughAHTest = Test<PenpalA, PenpalB, AssetHubPezkuwichain>;
|
||||
pub(crate) type RelayToParaThroughAHTest = Test<Pezkuwichain, PenpalA, AssetHubPezkuwichain>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// 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.
|
||||
|
||||
//! Tests related to claiming assets trapped during XCM execution.
|
||||
|
||||
use crate::imports::*;
|
||||
|
||||
use emulated_integration_tests_common::test_chain_can_claim_assets;
|
||||
|
||||
#[test]
|
||||
fn assets_can_be_claimed() {
|
||||
let amount = AssetHubPezkuwichainExistentialDeposit::get();
|
||||
let assets: Assets = (Parent, amount).into();
|
||||
|
||||
test_chain_can_claim_assets!(
|
||||
AssetHubPezkuwichain,
|
||||
RuntimeCall,
|
||||
NetworkId::ByGenesis(PEZKUWICHAIN_GENESIS_HASH),
|
||||
assets,
|
||||
amount
|
||||
);
|
||||
}
|
||||
+868
@@ -0,0 +1,868 @@
|
||||
// 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 super::reserve_transfer::*;
|
||||
use crate::{
|
||||
imports::*,
|
||||
tests::teleport::do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt,
|
||||
};
|
||||
|
||||
fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
let sov_penpal_a_on_ah = AssetHubPezkuwichain::sovereign_account_id_of(
|
||||
AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id()),
|
||||
);
|
||||
let sov_penpal_b_on_ah = AssetHubPezkuwichain::sovereign_account_id_of(
|
||||
AssetHubPezkuwichain::sibling_location_of(PenpalB::para_id()),
|
||||
);
|
||||
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
// Withdrawn from sender teyrchain SA
|
||||
RuntimeEvent::Balances(
|
||||
pezpallet_balances::Event::Burned { who, amount }
|
||||
) => {
|
||||
who: *who == sov_penpal_a_on_ah,
|
||||
amount: *amount == t.args.amount,
|
||||
},
|
||||
// Deposited to receiver teyrchain SA
|
||||
RuntimeEvent::Balances(
|
||||
pezpallet_balances::Event::Minted { who, .. }
|
||||
) => {
|
||||
who: *who == sov_penpal_b_on_ah,
|
||||
},
|
||||
RuntimeEvent::MessageQueue(
|
||||
pezpallet_message_queue::Event::Processed { success: true, .. }
|
||||
) => {},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
fn ah_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult {
|
||||
let fee: Asset = t
|
||||
.args
|
||||
.assets
|
||||
.inner()
|
||||
.iter()
|
||||
.find(|a| a.id == t.args.fee_asset_id)
|
||||
.cloned()
|
||||
.unwrap();
|
||||
let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset {
|
||||
assets: Wild(AllCounted(t.args.assets.len() as u32)),
|
||||
beneficiary: t.args.beneficiary,
|
||||
}]);
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::PezkuwiXcm::transfer_assets_using_type_and_then(
|
||||
t.signed_origin,
|
||||
bx!(t.args.dest.into()),
|
||||
bx!(t.args.assets.into()),
|
||||
bx!(TransferType::LocalReserve),
|
||||
bx!(fee.id.into()),
|
||||
bx!(TransferType::LocalReserve),
|
||||
bx!(VersionedXcm::from(custom_xcm_on_dest)),
|
||||
t.args.weight_limit,
|
||||
)
|
||||
}
|
||||
|
||||
fn para_to_ah_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult {
|
||||
let fee: Asset = t
|
||||
.args
|
||||
.assets
|
||||
.inner()
|
||||
.iter()
|
||||
.find(|a| a.id == t.args.fee_asset_id)
|
||||
.cloned()
|
||||
.unwrap();
|
||||
let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset {
|
||||
assets: Wild(AllCounted(t.args.assets.len() as u32)),
|
||||
beneficiary: t.args.beneficiary,
|
||||
}]);
|
||||
<PenpalA as PenpalAPallet>::PezkuwiXcm::transfer_assets_using_type_and_then(
|
||||
t.signed_origin,
|
||||
bx!(t.args.dest.into()),
|
||||
bx!(t.args.assets.into()),
|
||||
bx!(TransferType::DestinationReserve),
|
||||
bx!(fee.id.into()),
|
||||
bx!(TransferType::DestinationReserve),
|
||||
bx!(VersionedXcm::from(custom_xcm_on_dest)),
|
||||
t.args.weight_limit,
|
||||
)
|
||||
}
|
||||
|
||||
fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> DispatchResult {
|
||||
let fee: Asset = t
|
||||
.args
|
||||
.assets
|
||||
.inner()
|
||||
.iter()
|
||||
.find(|a| a.id == t.args.fee_asset_id)
|
||||
.cloned()
|
||||
.unwrap();
|
||||
let asset_hub_location: Location =
|
||||
PenpalA::sibling_location_of(AssetHubPezkuwichain::para_id());
|
||||
let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset {
|
||||
assets: Wild(AllCounted(t.args.assets.len() as u32)),
|
||||
beneficiary: t.args.beneficiary,
|
||||
}]);
|
||||
<PenpalA as PenpalAPallet>::PezkuwiXcm::transfer_assets_using_type_and_then(
|
||||
t.signed_origin,
|
||||
bx!(t.args.dest.into()),
|
||||
bx!(t.args.assets.into()),
|
||||
bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())),
|
||||
bx!(fee.id.into()),
|
||||
bx!(TransferType::RemoteReserve(asset_hub_location.into())),
|
||||
bx!(VersionedXcm::from(custom_xcm_on_dest)),
|
||||
t.args.weight_limit,
|
||||
)
|
||||
}
|
||||
|
||||
fn para_to_asset_hub_teleport_foreign_assets(t: ParaToSystemParaTest) -> DispatchResult {
|
||||
let fee: Asset = t
|
||||
.args
|
||||
.assets
|
||||
.inner()
|
||||
.iter()
|
||||
.find(|a| a.id == t.args.fee_asset_id)
|
||||
.cloned()
|
||||
.unwrap();
|
||||
let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset {
|
||||
assets: Wild(AllCounted(t.args.assets.len() as u32)),
|
||||
beneficiary: t.args.beneficiary,
|
||||
}]);
|
||||
<PenpalA as PenpalAPallet>::PezkuwiXcm::transfer_assets_using_type_and_then(
|
||||
t.signed_origin,
|
||||
bx!(t.args.dest.into()),
|
||||
bx!(t.args.assets.into()),
|
||||
bx!(TransferType::Teleport),
|
||||
bx!(fee.id.into()),
|
||||
bx!(TransferType::DestinationReserve),
|
||||
bx!(VersionedXcm::from(custom_xcm_on_dest)),
|
||||
t.args.weight_limit,
|
||||
)
|
||||
}
|
||||
|
||||
fn asset_hub_to_para_teleport_foreign_assets(t: SystemParaToParaTest) -> DispatchResult {
|
||||
let fee: Asset = t
|
||||
.args
|
||||
.assets
|
||||
.inner()
|
||||
.iter()
|
||||
.find(|a| a.id == t.args.fee_asset_id)
|
||||
.cloned()
|
||||
.unwrap();
|
||||
let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset {
|
||||
assets: Wild(AllCounted(t.args.assets.len() as u32)),
|
||||
beneficiary: t.args.beneficiary,
|
||||
}]);
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::PezkuwiXcm::transfer_assets_using_type_and_then(
|
||||
t.signed_origin,
|
||||
bx!(t.args.dest.into()),
|
||||
bx!(t.args.assets.into()),
|
||||
bx!(TransferType::Teleport),
|
||||
bx!(fee.id.into()),
|
||||
bx!(TransferType::LocalReserve),
|
||||
bx!(VersionedXcm::from(custom_xcm_on_dest)),
|
||||
t.args.weight_limit,
|
||||
)
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// ======= Transfer - Native + Bridged Assets - AssetHub->Teyrchain ==========
|
||||
// ===========================================================================
|
||||
/// Transfers of native asset plus bridged asset from AssetHub to some Teyrchain
|
||||
/// while paying fees using native asset.
|
||||
#[test]
|
||||
fn transfer_foreign_assets_from_asset_hub_to_para() {
|
||||
let destination = AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id());
|
||||
let sender = AssetHubPezkuwichainSender::get();
|
||||
let native_amount_to_send: Balance = ASSET_HUB_PEZKUWICHAIN_ED * 10000;
|
||||
let native_asset_location = RelayLocation::get();
|
||||
let receiver = PenpalAReceiver::get();
|
||||
let assets_owner = PenpalAssetOwner::get();
|
||||
// Foreign asset used: bridged ZGR
|
||||
let foreign_amount_to_send = ASSET_HUB_PEZKUWICHAIN_ED * 10_000_000;
|
||||
let wnd_at_pezkuwichain_teyrchains =
|
||||
Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(ZAGROS_GENESIS_HASH))]);
|
||||
|
||||
// Configure destination chain to trust AH as reserve of ZGR
|
||||
PenpalA::execute_with(|| {
|
||||
assert_ok!(<PenpalA as Chain>::System::set_storage(
|
||||
<PenpalA as Chain>::RuntimeOrigin::root(),
|
||||
vec![(
|
||||
PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(),
|
||||
Location::new(2, [GlobalConsensus(ByGenesis(ZAGROS_GENESIS_HASH))]).encode(),
|
||||
)],
|
||||
));
|
||||
});
|
||||
PenpalA::force_create_foreign_asset(
|
||||
wnd_at_pezkuwichain_teyrchains.clone(),
|
||||
assets_owner.clone(),
|
||||
false,
|
||||
ASSET_MIN_BALANCE,
|
||||
vec![],
|
||||
);
|
||||
AssetHubPezkuwichain::force_create_foreign_asset(
|
||||
wnd_at_pezkuwichain_teyrchains.clone().try_into().unwrap(),
|
||||
assets_owner.clone(),
|
||||
false,
|
||||
ASSET_MIN_BALANCE,
|
||||
vec![],
|
||||
);
|
||||
AssetHubPezkuwichain::mint_foreign_asset(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(assets_owner),
|
||||
wnd_at_pezkuwichain_teyrchains.clone().try_into().unwrap(),
|
||||
sender.clone(),
|
||||
foreign_amount_to_send * 2,
|
||||
);
|
||||
|
||||
// Assets to send
|
||||
let assets: Vec<Asset> = vec![
|
||||
(Parent, native_amount_to_send).into(),
|
||||
(wnd_at_pezkuwichain_teyrchains.clone(), foreign_amount_to_send).into(),
|
||||
];
|
||||
let fee_asset_id = AssetId(Parent.into());
|
||||
|
||||
// Init Test
|
||||
let test_args = TestContext {
|
||||
sender: sender.clone(),
|
||||
receiver: receiver.clone(),
|
||||
args: TestArgs::new_para(
|
||||
destination.clone(),
|
||||
receiver.clone(),
|
||||
native_amount_to_send,
|
||||
assets.into(),
|
||||
None,
|
||||
fee_asset_id,
|
||||
),
|
||||
};
|
||||
let mut test = SystemParaToParaTest::new(test_args);
|
||||
|
||||
// Query initial balances
|
||||
let sender_balance_before = test.sender.balance;
|
||||
let sender_wnds_before = AssetHubPezkuwichain::execute_with(|| {
|
||||
type ForeignAssets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(
|
||||
wnd_at_pezkuwichain_teyrchains.clone().try_into().unwrap(),
|
||||
&sender,
|
||||
)
|
||||
});
|
||||
let receiver_assets_before = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(native_asset_location.clone(), &receiver)
|
||||
});
|
||||
let receiver_wnds_before = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(wnd_at_pezkuwichain_teyrchains.clone(), &receiver)
|
||||
});
|
||||
|
||||
// Set assertions and dispatchables
|
||||
test.set_assertion::<AssetHubPezkuwichain>(system_para_to_para_sender_assertions);
|
||||
test.set_assertion::<PenpalA>(system_para_to_para_receiver_assertions);
|
||||
test.set_dispatchable::<AssetHubPezkuwichain>(ah_to_para_transfer_assets);
|
||||
test.assert();
|
||||
|
||||
// Query final balances
|
||||
let sender_balance_after = test.sender.balance;
|
||||
let sender_wnds_after = AssetHubPezkuwichain::execute_with(|| {
|
||||
type ForeignAssets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(
|
||||
wnd_at_pezkuwichain_teyrchains.clone().try_into().unwrap(),
|
||||
&sender,
|
||||
)
|
||||
});
|
||||
let receiver_assets_after = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(native_asset_location, &receiver)
|
||||
});
|
||||
let receiver_wnds_after = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(wnd_at_pezkuwichain_teyrchains, &receiver)
|
||||
});
|
||||
|
||||
// Sender's balance is reduced by amount sent plus delivery fees
|
||||
assert!(sender_balance_after < sender_balance_before - native_amount_to_send);
|
||||
// Sender's balance is reduced by foreign amount sent
|
||||
assert_eq!(sender_wnds_after, sender_wnds_before - foreign_amount_to_send);
|
||||
// Receiver's assets is increased
|
||||
assert!(receiver_assets_after > receiver_assets_before);
|
||||
// Receiver's assets increased by `amount_to_send - delivery_fees - bought_execution`;
|
||||
// `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but
|
||||
// should be non-zero
|
||||
assert!(receiver_assets_after < receiver_assets_before + native_amount_to_send);
|
||||
// Receiver's balance is increased by foreign amount sent
|
||||
assert_eq!(receiver_wnds_after, receiver_wnds_before + foreign_amount_to_send);
|
||||
}
|
||||
|
||||
/// Reserve Transfers of native asset from Teyrchain to System Teyrchain should work
|
||||
// ===========================================================================
|
||||
// ======= Transfer - Native + Bridged Assets - Teyrchain->AssetHub ==========
|
||||
// ===========================================================================
|
||||
/// Transfers of native asset plus bridged asset from some Teyrchain to AssetHub
|
||||
/// while paying fees using native asset.
|
||||
#[test]
|
||||
fn transfer_foreign_assets_from_para_to_asset_hub() {
|
||||
// Init values for Teyrchain
|
||||
let destination = PenpalA::sibling_location_of(AssetHubPezkuwichain::para_id());
|
||||
let sender = PenpalASender::get();
|
||||
let native_amount_to_send: Balance = ASSET_HUB_PEZKUWICHAIN_ED * 10000;
|
||||
let native_asset_location = RelayLocation::get();
|
||||
let assets_owner = PenpalAssetOwner::get();
|
||||
|
||||
// Foreign asset used: bridged ZGR
|
||||
let foreign_amount_to_send = ASSET_HUB_PEZKUWICHAIN_ED * 10_000_000;
|
||||
let wnd_at_pezkuwichain_teyrchains =
|
||||
Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(ZAGROS_GENESIS_HASH))]);
|
||||
|
||||
// Configure destination chain to trust AH as reserve of ZGR
|
||||
PenpalA::execute_with(|| {
|
||||
assert_ok!(<PenpalA as Chain>::System::set_storage(
|
||||
<PenpalA as Chain>::RuntimeOrigin::root(),
|
||||
vec![(
|
||||
PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(),
|
||||
Location::new(2, [GlobalConsensus(ByGenesis(ZAGROS_GENESIS_HASH))]).encode(),
|
||||
)],
|
||||
));
|
||||
});
|
||||
PenpalA::force_create_foreign_asset(
|
||||
wnd_at_pezkuwichain_teyrchains.clone(),
|
||||
assets_owner.clone(),
|
||||
false,
|
||||
ASSET_MIN_BALANCE,
|
||||
vec![],
|
||||
);
|
||||
AssetHubPezkuwichain::force_create_foreign_asset(
|
||||
wnd_at_pezkuwichain_teyrchains.clone().try_into().unwrap(),
|
||||
assets_owner.clone(),
|
||||
false,
|
||||
ASSET_MIN_BALANCE,
|
||||
vec![],
|
||||
);
|
||||
|
||||
// fund Teyrchain's sender account
|
||||
PenpalA::mint_foreign_asset(
|
||||
<PenpalA as Chain>::RuntimeOrigin::signed(assets_owner.clone()),
|
||||
native_asset_location.clone(),
|
||||
sender.clone(),
|
||||
native_amount_to_send * 2,
|
||||
);
|
||||
PenpalA::mint_foreign_asset(
|
||||
<PenpalA as Chain>::RuntimeOrigin::signed(assets_owner.clone()),
|
||||
wnd_at_pezkuwichain_teyrchains.clone(),
|
||||
sender.clone(),
|
||||
foreign_amount_to_send * 2,
|
||||
);
|
||||
|
||||
// Init values for System Teyrchain
|
||||
let receiver = AssetHubPezkuwichainReceiver::get();
|
||||
let penpal_location_as_seen_by_ahr =
|
||||
AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id());
|
||||
let sov_penpal_on_ahr =
|
||||
AssetHubPezkuwichain::sovereign_account_id_of(penpal_location_as_seen_by_ahr);
|
||||
|
||||
// fund Teyrchain's SA on AssetHub with the assets held in reserve
|
||||
AssetHubPezkuwichain::fund_accounts(vec![(
|
||||
sov_penpal_on_ahr.clone().into(),
|
||||
native_amount_to_send * 2,
|
||||
)]);
|
||||
AssetHubPezkuwichain::mint_foreign_asset(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(assets_owner),
|
||||
wnd_at_pezkuwichain_teyrchains.clone().try_into().unwrap(),
|
||||
sov_penpal_on_ahr,
|
||||
foreign_amount_to_send * 2,
|
||||
);
|
||||
|
||||
// Assets to send
|
||||
let assets: Vec<Asset> = vec![
|
||||
(Parent, native_amount_to_send).into(),
|
||||
(wnd_at_pezkuwichain_teyrchains.clone(), foreign_amount_to_send).into(),
|
||||
];
|
||||
let fee_asset_id = AssetId(Parent.into());
|
||||
|
||||
// Init Test
|
||||
let test_args = TestContext {
|
||||
sender: sender.clone(),
|
||||
receiver: receiver.clone(),
|
||||
args: TestArgs::new_para(
|
||||
destination.clone(),
|
||||
receiver.clone(),
|
||||
native_amount_to_send,
|
||||
assets.into(),
|
||||
None,
|
||||
fee_asset_id,
|
||||
),
|
||||
};
|
||||
let mut test = ParaToSystemParaTest::new(test_args);
|
||||
|
||||
// Query initial balances
|
||||
let sender_native_before = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(native_asset_location.clone(), &sender)
|
||||
});
|
||||
let sender_wnds_before = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(wnd_at_pezkuwichain_teyrchains.clone(), &sender)
|
||||
});
|
||||
let receiver_native_before = test.receiver.balance;
|
||||
let receiver_wnds_before = AssetHubPezkuwichain::execute_with(|| {
|
||||
type ForeignAssets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(
|
||||
wnd_at_pezkuwichain_teyrchains.clone().try_into().unwrap(),
|
||||
&receiver,
|
||||
)
|
||||
});
|
||||
|
||||
// Set assertions and dispatchables
|
||||
test.set_assertion::<PenpalA>(para_to_system_para_sender_assertions);
|
||||
test.set_assertion::<AssetHubPezkuwichain>(para_to_system_para_receiver_assertions);
|
||||
test.set_dispatchable::<PenpalA>(para_to_ah_transfer_assets);
|
||||
test.assert();
|
||||
|
||||
// Query final balances
|
||||
let sender_native_after = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(native_asset_location, &sender)
|
||||
});
|
||||
let sender_wnds_after = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(wnd_at_pezkuwichain_teyrchains.clone(), &sender)
|
||||
});
|
||||
let receiver_native_after = test.receiver.balance;
|
||||
let receiver_wnds_after = AssetHubPezkuwichain::execute_with(|| {
|
||||
type ForeignAssets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(
|
||||
wnd_at_pezkuwichain_teyrchains.try_into().unwrap(),
|
||||
&receiver,
|
||||
)
|
||||
});
|
||||
|
||||
// Sender's balance is reduced by amount sent plus delivery fees
|
||||
assert!(sender_native_after < sender_native_before - native_amount_to_send);
|
||||
// Sender's balance is reduced by foreign amount sent
|
||||
assert_eq!(sender_wnds_after, sender_wnds_before - foreign_amount_to_send);
|
||||
// Receiver's balance is increased
|
||||
assert!(receiver_native_after > receiver_native_before);
|
||||
// Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`;
|
||||
// `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but
|
||||
// should be non-zero
|
||||
assert!(receiver_native_after < receiver_native_before + native_amount_to_send);
|
||||
// Receiver's balance is increased by foreign amount sent
|
||||
assert_eq!(receiver_wnds_after, receiver_wnds_before + foreign_amount_to_send);
|
||||
}
|
||||
|
||||
// ==============================================================================
|
||||
// ===== Transfer - Native + Bridged Assets - Teyrchain->AssetHub->Teyrchain ====
|
||||
// ==============================================================================
|
||||
/// Transfers of native asset plus bridged asset from Teyrchain to Teyrchain
|
||||
/// (through AssetHub reserve) with fees paid using native asset.
|
||||
#[test]
|
||||
fn transfer_foreign_assets_from_para_to_para_through_asset_hub() {
|
||||
// Init values for Teyrchain Origin
|
||||
let destination = PenpalA::sibling_location_of(PenpalB::para_id());
|
||||
let sender = PenpalASender::get();
|
||||
let roc_to_send: Balance = PEZKUWICHAIN_ED * 10000;
|
||||
let assets_owner = PenpalAssetOwner::get();
|
||||
let roc_location = RelayLocation::get();
|
||||
let sender_as_seen_by_ah = AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id());
|
||||
let sov_of_sender_on_ah = AssetHubPezkuwichain::sovereign_account_id_of(sender_as_seen_by_ah);
|
||||
let receiver_as_seen_by_ah = AssetHubPezkuwichain::sibling_location_of(PenpalB::para_id());
|
||||
let sov_of_receiver_on_ah =
|
||||
AssetHubPezkuwichain::sovereign_account_id_of(receiver_as_seen_by_ah);
|
||||
let wnd_to_send = ASSET_HUB_PEZKUWICHAIN_ED * 10_000_000;
|
||||
|
||||
// Configure source and destination chains to trust AH as reserve of ZGR
|
||||
PenpalA::execute_with(|| {
|
||||
assert_ok!(<PenpalA as Chain>::System::set_storage(
|
||||
<PenpalA as Chain>::RuntimeOrigin::root(),
|
||||
vec![(
|
||||
PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(),
|
||||
Location::new(2, [GlobalConsensus(ByGenesis(ZAGROS_GENESIS_HASH))]).encode(),
|
||||
)],
|
||||
));
|
||||
});
|
||||
PenpalB::execute_with(|| {
|
||||
assert_ok!(<PenpalB as Chain>::System::set_storage(
|
||||
<PenpalB as Chain>::RuntimeOrigin::root(),
|
||||
vec![(
|
||||
PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(),
|
||||
Location::new(2, [GlobalConsensus(ByGenesis(ZAGROS_GENESIS_HASH))]).encode(),
|
||||
)],
|
||||
));
|
||||
});
|
||||
|
||||
// Register ZGR as foreign asset and transfer it around the Pezkuwichain ecosystem
|
||||
let wnd_at_pezkuwichain_teyrchains =
|
||||
Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(ZAGROS_GENESIS_HASH))]);
|
||||
AssetHubPezkuwichain::force_create_foreign_asset(
|
||||
wnd_at_pezkuwichain_teyrchains.clone().try_into().unwrap(),
|
||||
assets_owner.clone(),
|
||||
false,
|
||||
ASSET_MIN_BALANCE,
|
||||
vec![],
|
||||
);
|
||||
PenpalA::force_create_foreign_asset(
|
||||
wnd_at_pezkuwichain_teyrchains.clone(),
|
||||
assets_owner.clone(),
|
||||
false,
|
||||
ASSET_MIN_BALANCE,
|
||||
vec![],
|
||||
);
|
||||
PenpalB::force_create_foreign_asset(
|
||||
wnd_at_pezkuwichain_teyrchains.clone(),
|
||||
assets_owner.clone(),
|
||||
false,
|
||||
ASSET_MIN_BALANCE,
|
||||
vec![],
|
||||
);
|
||||
|
||||
// fund Teyrchain's sender account
|
||||
PenpalA::mint_foreign_asset(
|
||||
<PenpalA as Chain>::RuntimeOrigin::signed(assets_owner.clone()),
|
||||
roc_location.clone(),
|
||||
sender.clone(),
|
||||
roc_to_send * 2,
|
||||
);
|
||||
PenpalA::mint_foreign_asset(
|
||||
<PenpalA as Chain>::RuntimeOrigin::signed(assets_owner.clone()),
|
||||
wnd_at_pezkuwichain_teyrchains.clone(),
|
||||
sender.clone(),
|
||||
wnd_to_send * 2,
|
||||
);
|
||||
// fund the Teyrchain Origin's SA on Asset Hub with the assets held in reserve
|
||||
AssetHubPezkuwichain::fund_accounts(vec![(
|
||||
sov_of_sender_on_ah.clone().into(),
|
||||
roc_to_send * 2,
|
||||
)]);
|
||||
AssetHubPezkuwichain::mint_foreign_asset(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(assets_owner),
|
||||
wnd_at_pezkuwichain_teyrchains.clone().try_into().unwrap(),
|
||||
sov_of_sender_on_ah.clone(),
|
||||
wnd_to_send * 2,
|
||||
);
|
||||
|
||||
// Init values for Teyrchain Destination
|
||||
let receiver = PenpalBReceiver::get();
|
||||
|
||||
// Assets to send
|
||||
let assets: Vec<Asset> = vec![
|
||||
(roc_location.clone(), roc_to_send).into(),
|
||||
(wnd_at_pezkuwichain_teyrchains.clone(), wnd_to_send).into(),
|
||||
];
|
||||
let fee_asset_id: AssetId = roc_location.clone().into();
|
||||
|
||||
// Init Test
|
||||
let test_args = TestContext {
|
||||
sender: sender.clone(),
|
||||
receiver: receiver.clone(),
|
||||
args: TestArgs::new_para(
|
||||
destination,
|
||||
receiver.clone(),
|
||||
roc_to_send,
|
||||
assets.into(),
|
||||
None,
|
||||
fee_asset_id,
|
||||
),
|
||||
};
|
||||
let mut test = ParaToParaThroughAHTest::new(test_args);
|
||||
|
||||
// Query initial balances
|
||||
let sender_rocs_before = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(roc_location.clone(), &sender)
|
||||
});
|
||||
let sender_wnds_before = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(wnd_at_pezkuwichain_teyrchains.clone(), &sender)
|
||||
});
|
||||
let rocs_in_sender_reserve_on_ahr_before =
|
||||
<AssetHubPezkuwichain as Chain>::account_data_of(sov_of_sender_on_ah.clone()).free;
|
||||
let wnds_in_sender_reserve_on_ahr_before = AssetHubPezkuwichain::execute_with(|| {
|
||||
type Assets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
|
||||
<Assets as Inspect<_>>::balance(
|
||||
wnd_at_pezkuwichain_teyrchains.clone().try_into().unwrap(),
|
||||
&sov_of_sender_on_ah,
|
||||
)
|
||||
});
|
||||
let rocs_in_receiver_reserve_on_ahr_before =
|
||||
<AssetHubPezkuwichain as Chain>::account_data_of(sov_of_receiver_on_ah.clone()).free;
|
||||
let wnds_in_receiver_reserve_on_ahr_before = AssetHubPezkuwichain::execute_with(|| {
|
||||
type Assets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
|
||||
<Assets as Inspect<_>>::balance(
|
||||
wnd_at_pezkuwichain_teyrchains.clone().try_into().unwrap(),
|
||||
&sov_of_receiver_on_ah,
|
||||
)
|
||||
});
|
||||
let receiver_rocs_before = PenpalB::execute_with(|| {
|
||||
type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(roc_location.clone(), &receiver)
|
||||
});
|
||||
let receiver_wnds_before = PenpalB::execute_with(|| {
|
||||
type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(wnd_at_pezkuwichain_teyrchains.clone(), &receiver)
|
||||
});
|
||||
|
||||
// Set assertions and dispatchables
|
||||
test.set_assertion::<PenpalA>(para_to_para_through_hop_sender_assertions);
|
||||
test.set_assertion::<AssetHubPezkuwichain>(para_to_para_assethub_hop_assertions);
|
||||
test.set_assertion::<PenpalB>(para_to_para_through_hop_receiver_assertions);
|
||||
test.set_dispatchable::<PenpalA>(para_to_para_transfer_assets_through_ah);
|
||||
test.assert();
|
||||
|
||||
// Query final balances
|
||||
let sender_rocs_after = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(roc_location.clone(), &sender)
|
||||
});
|
||||
let sender_wnds_after = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(wnd_at_pezkuwichain_teyrchains.clone(), &sender)
|
||||
});
|
||||
let wnds_in_sender_reserve_on_ahr_after = AssetHubPezkuwichain::execute_with(|| {
|
||||
type Assets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
|
||||
<Assets as Inspect<_>>::balance(
|
||||
wnd_at_pezkuwichain_teyrchains.clone().try_into().unwrap(),
|
||||
&sov_of_sender_on_ah,
|
||||
)
|
||||
});
|
||||
let rocs_in_sender_reserve_on_ahr_after =
|
||||
<AssetHubPezkuwichain as Chain>::account_data_of(sov_of_sender_on_ah).free;
|
||||
let wnds_in_receiver_reserve_on_ahr_after = AssetHubPezkuwichain::execute_with(|| {
|
||||
type Assets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
|
||||
<Assets as Inspect<_>>::balance(
|
||||
wnd_at_pezkuwichain_teyrchains.clone().try_into().unwrap(),
|
||||
&sov_of_receiver_on_ah,
|
||||
)
|
||||
});
|
||||
let rocs_in_receiver_reserve_on_ahr_after =
|
||||
<AssetHubPezkuwichain as Chain>::account_data_of(sov_of_receiver_on_ah).free;
|
||||
let receiver_rocs_after = PenpalB::execute_with(|| {
|
||||
type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(roc_location, &receiver)
|
||||
});
|
||||
let receiver_wnds_after = PenpalB::execute_with(|| {
|
||||
type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(wnd_at_pezkuwichain_teyrchains, &receiver)
|
||||
});
|
||||
|
||||
// Sender's balance is reduced by amount sent plus delivery fees
|
||||
assert!(sender_rocs_after < sender_rocs_before - roc_to_send);
|
||||
assert_eq!(sender_wnds_after, sender_wnds_before - wnd_to_send);
|
||||
// Sovereign accounts on reserve are changed accordingly
|
||||
assert_eq!(
|
||||
rocs_in_sender_reserve_on_ahr_after,
|
||||
rocs_in_sender_reserve_on_ahr_before - roc_to_send
|
||||
);
|
||||
assert_eq!(
|
||||
wnds_in_sender_reserve_on_ahr_after,
|
||||
wnds_in_sender_reserve_on_ahr_before - wnd_to_send
|
||||
);
|
||||
assert!(rocs_in_receiver_reserve_on_ahr_after > rocs_in_receiver_reserve_on_ahr_before);
|
||||
assert_eq!(
|
||||
wnds_in_receiver_reserve_on_ahr_after,
|
||||
wnds_in_receiver_reserve_on_ahr_before + wnd_to_send
|
||||
);
|
||||
// Receiver's balance is increased
|
||||
assert!(receiver_rocs_after > receiver_rocs_before);
|
||||
assert_eq!(receiver_wnds_after, receiver_wnds_before + wnd_to_send);
|
||||
}
|
||||
|
||||
// ==============================================================================================
|
||||
// ==== Bidirectional Transfer - Native + Teleportable Foreign Assets - Teyrchain<->AssetHub ====
|
||||
// ==============================================================================================
|
||||
/// Transfers of native asset plus teleportable foreign asset from Teyrchain to AssetHub and back
|
||||
/// with fees paid using native asset.
|
||||
#[test]
|
||||
fn bidirectional_teleport_foreign_asset_between_para_and_asset_hub_using_explicit_transfer_types() {
|
||||
do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt(
|
||||
para_to_asset_hub_teleport_foreign_assets,
|
||||
asset_hub_to_para_teleport_foreign_assets,
|
||||
);
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// ===== Transfer - Native Asset - Relay->AssetHub->Teyrchain ====
|
||||
// ===============================================================
|
||||
/// Transfers of native asset Relay to Teyrchain (using AssetHub reserve). Teyrchains want to avoid
|
||||
/// managing SAs on all system chains, thus want all their HEZ-in-reserve to be held in their
|
||||
/// Sovereign Account on Asset Hub.
|
||||
#[test]
|
||||
fn transfer_native_asset_from_relay_to_para_through_asset_hub() {
|
||||
// Init values for Relay
|
||||
let destination = Pezkuwichain::child_location_of(PenpalA::para_id());
|
||||
let sender = PezkuwichainSender::get();
|
||||
let amount_to_send: Balance = PEZKUWICHAIN_ED * 1000;
|
||||
|
||||
// Init values for Teyrchain
|
||||
let relay_native_asset_location = RelayLocation::get();
|
||||
let receiver = PenpalAReceiver::get();
|
||||
|
||||
// Init Test
|
||||
let test_args = TestContext {
|
||||
sender,
|
||||
receiver: receiver.clone(),
|
||||
args: TestArgs::new_relay(destination.clone(), receiver.clone(), amount_to_send),
|
||||
};
|
||||
let mut test = RelayToParaThroughAHTest::new(test_args);
|
||||
|
||||
let sov_penpal_on_ah = AssetHubPezkuwichain::sovereign_account_id_of(
|
||||
AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id()),
|
||||
);
|
||||
// Query initial balances
|
||||
let sender_balance_before = test.sender.balance;
|
||||
let sov_penpal_on_ah_before = AssetHubPezkuwichain::execute_with(|| {
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Balances::free_balance(
|
||||
sov_penpal_on_ah.clone(),
|
||||
)
|
||||
});
|
||||
let receiver_assets_before = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(relay_native_asset_location.clone(), &receiver)
|
||||
});
|
||||
|
||||
fn relay_assertions(t: RelayToParaThroughAHTest) {
|
||||
type RuntimeEvent = <Pezkuwichain as Chain>::RuntimeEvent;
|
||||
Pezkuwichain::assert_xcm_pallet_attempted_complete(None);
|
||||
assert_expected_events!(
|
||||
Pezkuwichain,
|
||||
vec![
|
||||
// Amount to teleport is withdrawn from Sender
|
||||
RuntimeEvent::Balances(pezpallet_balances::Event::Burned { who, amount }) => {
|
||||
who: *who == t.sender.account_id,
|
||||
amount: *amount == t.args.amount,
|
||||
},
|
||||
// Amount to teleport is deposited in Relay's `CheckAccount`
|
||||
RuntimeEvent::Balances(pezpallet_balances::Event::Minted { who, amount }) => {
|
||||
who: *who == <Pezkuwichain as PezkuwichainPallet>::XcmPallet::check_account(),
|
||||
amount: *amount == t.args.amount,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
fn asset_hub_assertions(_: RelayToParaThroughAHTest) {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
let sov_penpal_on_ah = AssetHubPezkuwichain::sovereign_account_id_of(
|
||||
AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id()),
|
||||
);
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
// Deposited to receiver teyrchain SA
|
||||
RuntimeEvent::Balances(
|
||||
pezpallet_balances::Event::Minted { who, .. }
|
||||
) => {
|
||||
who: *who == sov_penpal_on_ah,
|
||||
},
|
||||
RuntimeEvent::MessageQueue(
|
||||
pezpallet_message_queue::Event::Processed { success: true, .. }
|
||||
) => {},
|
||||
]
|
||||
);
|
||||
}
|
||||
fn penpal_assertions(t: RelayToParaThroughAHTest) {
|
||||
type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
|
||||
// Assets in t are relative to the relay chain. The asset here should be relative to
|
||||
// Penpal, so parents: 1.
|
||||
let expected_id: Location = Location { parents: 1, interior: Here };
|
||||
|
||||
assert_expected_events!(
|
||||
PenpalA,
|
||||
vec![
|
||||
RuntimeEvent::ForeignAssets(pezpallet_assets::Event::Issued { asset_id, owner, .. }) => {
|
||||
asset_id: *asset_id == expected_id,
|
||||
owner: *owner == t.receiver.account_id,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
fn transfer_assets_dispatchable(t: RelayToParaThroughAHTest) -> DispatchResult {
|
||||
let fee: Asset = t
|
||||
.args
|
||||
.assets
|
||||
.inner()
|
||||
.iter()
|
||||
.find(|a| a.id == t.args.fee_asset_id)
|
||||
.cloned()
|
||||
.unwrap();
|
||||
let asset_hub_location = Pezkuwichain::child_location_of(AssetHubPezkuwichain::para_id());
|
||||
let context = PezkuwichainUniversalLocation::get();
|
||||
|
||||
// reanchor fees to the view of destination (Penpal)
|
||||
let mut remote_fees = fee.clone().reanchored(&t.args.dest, &context).unwrap();
|
||||
if let Fungible(ref mut amount) = remote_fees.fun {
|
||||
// we already spent some fees along the way, just use half of what we started with
|
||||
*amount = *amount / 2;
|
||||
}
|
||||
let xcm_on_final_dest = Xcm::<()>(vec![
|
||||
BuyExecution { fees: remote_fees, weight_limit: t.args.weight_limit.clone() },
|
||||
DepositAsset {
|
||||
assets: Wild(AllCounted(t.args.assets.len() as u32)),
|
||||
beneficiary: t.args.beneficiary,
|
||||
},
|
||||
]);
|
||||
|
||||
// reanchor final dest (Penpal) to the view of hop (Asset Hub)
|
||||
let mut dest = t.args.dest.clone();
|
||||
dest.reanchor(&asset_hub_location, &context).unwrap();
|
||||
// on Asset Hub, forward assets to Penpal
|
||||
let xcm_on_hop = Xcm::<()>(vec![DepositReserveAsset {
|
||||
assets: Wild(AllCounted(t.args.assets.len() as u32)),
|
||||
dest,
|
||||
xcm: xcm_on_final_dest,
|
||||
}]);
|
||||
|
||||
Dmp::make_teyrchain_reachable(AssetHubPezkuwichain::para_id());
|
||||
|
||||
// First leg is a teleport, from there a local-reserve-transfer to final dest
|
||||
<Pezkuwichain as PezkuwichainPallet>::XcmPallet::transfer_assets_using_type_and_then(
|
||||
t.signed_origin,
|
||||
bx!(asset_hub_location.into()),
|
||||
bx!(t.args.assets.into()),
|
||||
bx!(TransferType::Teleport),
|
||||
bx!(fee.id.into()),
|
||||
bx!(TransferType::Teleport),
|
||||
bx!(VersionedXcm::from(xcm_on_hop)),
|
||||
t.args.weight_limit,
|
||||
)
|
||||
}
|
||||
|
||||
// Set assertions and dispatchables
|
||||
test.set_assertion::<Pezkuwichain>(relay_assertions);
|
||||
test.set_assertion::<AssetHubPezkuwichain>(asset_hub_assertions);
|
||||
test.set_assertion::<PenpalA>(penpal_assertions);
|
||||
test.set_dispatchable::<Pezkuwichain>(transfer_assets_dispatchable);
|
||||
test.assert();
|
||||
|
||||
// Query final balances
|
||||
let sender_balance_after = test.sender.balance;
|
||||
let sov_penpal_on_ah_after = AssetHubPezkuwichain::execute_with(|| {
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Balances::free_balance(
|
||||
sov_penpal_on_ah,
|
||||
)
|
||||
});
|
||||
let receiver_assets_after = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(relay_native_asset_location, &receiver)
|
||||
});
|
||||
|
||||
// Sender's balance is reduced by amount sent plus delivery fees
|
||||
assert!(sender_balance_after < sender_balance_before - amount_to_send);
|
||||
// SA on AH balance is increased
|
||||
assert!(sov_penpal_on_ah_after > sov_penpal_on_ah_before);
|
||||
// Receiver's asset balance is increased
|
||||
assert!(receiver_assets_after > receiver_assets_before);
|
||||
// Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`;
|
||||
// `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but
|
||||
// should be non-zero
|
||||
assert!(receiver_assets_after < receiver_assets_before + amount_to_send);
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
// 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.
|
||||
|
||||
mod claim_assets;
|
||||
mod hybrid_transfers;
|
||||
mod reserve_transfer;
|
||||
mod reward_pool;
|
||||
mod send;
|
||||
mod set_xcm_versions;
|
||||
mod swap;
|
||||
mod teleport;
|
||||
mod treasury;
|
||||
mod xcm_fee_estimation;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! create_pool_with_roc_on {
|
||||
// default amounts
|
||||
( $chain:ident, $asset_id:expr, $is_foreign:expr, $asset_owner:expr ) => {
|
||||
$crate::create_pool_with_roc_on!(
|
||||
$chain,
|
||||
$asset_id,
|
||||
$is_foreign,
|
||||
$asset_owner,
|
||||
1_000_000_000_000,
|
||||
2_000_000_000_000
|
||||
);
|
||||
};
|
||||
|
||||
// custom amounts
|
||||
( $chain:ident, $asset_id:expr, $is_foreign:expr, $asset_owner:expr, $roc_amount:expr, $asset_amount: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 roc_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(roc_location.clone()),
|
||||
Box::new($asset_id.clone()),
|
||||
));
|
||||
|
||||
assert_expected_events!(
|
||||
$chain,
|
||||
vec![
|
||||
RuntimeEvent::AssetConversion(pezpallet_asset_conversion::Event::PoolCreated { .. }) => {},
|
||||
]
|
||||
);
|
||||
|
||||
assert_ok!(<$chain as [<$chain Pallet>]>::AssetConversion::add_liquidity(
|
||||
signed_owner,
|
||||
Box::new(roc_location),
|
||||
Box::new($asset_id),
|
||||
$roc_amount,
|
||||
$asset_amount,
|
||||
0,
|
||||
0,
|
||||
owner.into()
|
||||
));
|
||||
|
||||
assert_expected_events!(
|
||||
$chain,
|
||||
vec![
|
||||
RuntimeEvent::AssetConversion(pezpallet_asset_conversion::Event::LiquidityAdded { .. }) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
+1711
File diff suppressed because it is too large
Load Diff
+114
@@ -0,0 +1,114 @@
|
||||
// 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::imports::*;
|
||||
use pezframe_support::{pezsp_runtime::traits::Dispatchable, traits::schedule::DispatchTime};
|
||||
use xcm_executor::traits::ConvertLocation;
|
||||
|
||||
#[test]
|
||||
fn treasury_creates_asset_reward_pool() {
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
type Balances = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Balances;
|
||||
|
||||
let treasurer =
|
||||
Location::new(1, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]);
|
||||
let treasurer_account =
|
||||
ahr_xcm_config::LocationToAccountId::convert_location(&treasurer).unwrap();
|
||||
|
||||
assert_ok!(Balances::force_set_balance(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::root(),
|
||||
treasurer_account.clone().into(),
|
||||
ASSET_HUB_PEZKUWICHAIN_ED * 100_000,
|
||||
));
|
||||
|
||||
let events = AssetHubPezkuwichain::events();
|
||||
match events.iter().last() {
|
||||
Some(RuntimeEvent::Balances(pezpallet_balances::Event::BalanceSet { who, .. })) => {
|
||||
assert_eq!(*who, treasurer_account)
|
||||
},
|
||||
_ => panic!("Expected Balances::BalanceSet event"),
|
||||
}
|
||||
});
|
||||
|
||||
Pezkuwichain::execute_with(|| {
|
||||
type AssetHubPezkuwichainRuntimeCall = <AssetHubPezkuwichain as Chain>::RuntimeCall;
|
||||
type AssetHubPezkuwichainRuntime = <AssetHubPezkuwichain as Chain>::Runtime;
|
||||
type PezkuwichainRuntimeCall = <Pezkuwichain as Chain>::RuntimeCall;
|
||||
type PezkuwichainRuntime = <Pezkuwichain as Chain>::Runtime;
|
||||
type PezkuwichainRuntimeEvent = <Pezkuwichain as Chain>::RuntimeEvent;
|
||||
type PezkuwichainRuntimeOrigin = <Pezkuwichain as Chain>::RuntimeOrigin;
|
||||
|
||||
Dmp::make_teyrchain_reachable(AssetHubPezkuwichain::para_id());
|
||||
|
||||
let staked_asset_id = bx!(RelayLocation::get());
|
||||
let reward_asset_id = bx!(RelayLocation::get());
|
||||
|
||||
let reward_rate_per_block = 1_000_000_000;
|
||||
let lifetime = 1_000_000_000;
|
||||
let admin = None;
|
||||
|
||||
let create_pool_call =
|
||||
PezkuwichainRuntimeCall::XcmPallet(pezpallet_xcm::Call::<PezkuwichainRuntime>::send {
|
||||
dest: bx!(VersionedLocation::V4(
|
||||
xcm::v4::Junction::Teyrchain(AssetHubPezkuwichain::para_id().into()).into()
|
||||
)),
|
||||
message: bx!(VersionedXcm::V5(Xcm(vec![
|
||||
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
||||
Transact {
|
||||
origin_kind: OriginKind::SovereignAccount,
|
||||
fallback_max_weight: None,
|
||||
call: AssetHubPezkuwichainRuntimeCall::AssetRewards(
|
||||
pezpallet_asset_rewards::Call::<AssetHubPezkuwichainRuntime>::create_pool {
|
||||
staked_asset_id,
|
||||
reward_asset_id,
|
||||
reward_rate_per_block,
|
||||
expiry: DispatchTime::After(lifetime),
|
||||
admin
|
||||
}
|
||||
)
|
||||
.encode()
|
||||
.into(),
|
||||
}
|
||||
]))),
|
||||
});
|
||||
|
||||
let treasury_origin: PezkuwichainRuntimeOrigin = Treasurer.into();
|
||||
assert_ok!(create_pool_call.dispatch(treasury_origin));
|
||||
|
||||
assert_expected_events!(
|
||||
Pezkuwichain,
|
||||
vec![
|
||||
PezkuwichainRuntimeEvent::XcmPallet(pezpallet_xcm::Event::Sent { .. }) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
type Runtime = <AssetHubPezkuwichain as Chain>::Runtime;
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
|
||||
assert_eq!(1, pezpallet_asset_rewards::Pools::<Runtime>::iter().count());
|
||||
|
||||
let events = AssetHubPezkuwichain::events();
|
||||
match events.iter().last() {
|
||||
Some(RuntimeEvent::MessageQueue(pezpallet_message_queue::Event::Processed {
|
||||
success: true,
|
||||
..
|
||||
})) => (),
|
||||
_ => panic!("Expected MessageQueue::Processed event"),
|
||||
}
|
||||
});
|
||||
}
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
// 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_roc_on, imports::*};
|
||||
|
||||
/// Relay Chain should be able to execute `Transact` instructions in System Teyrchain
|
||||
/// when `OriginKind::Superuser`.
|
||||
#[test]
|
||||
fn send_transact_as_superuser_from_relay_to_asset_hub_works() {
|
||||
AssetHubPezkuwichain::force_create_asset_from_relay_as_root(
|
||||
ASSET_ID,
|
||||
ASSET_MIN_BALANCE,
|
||||
true,
|
||||
AssetHubPezkuwichainSender::get().into(),
|
||||
Some(Weight::from_parts(144_933_000, 3675)),
|
||||
)
|
||||
}
|
||||
|
||||
/// We tests two things here:
|
||||
/// - Teyrchain should be able to send XCM paying its fee at Asset Hub using system asset
|
||||
/// - Teyrchain should be able to create a new Foreign Asset at Asset Hub
|
||||
#[test]
|
||||
fn send_xcm_from_para_to_asset_hub_paying_fee_with_system_asset() {
|
||||
let para_sovereign_account = AssetHubPezkuwichain::sovereign_account_id_of(
|
||||
AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id()),
|
||||
);
|
||||
let asset_location_on_penpal = Location::new(
|
||||
0,
|
||||
[Junction::PalletInstance(ASSETS_PALLET_ID), Junction::GeneralIndex(ASSET_ID.into())],
|
||||
);
|
||||
let foreign_asset_at_asset_hub =
|
||||
Location::new(1, [Junction::Teyrchain(PenpalA::para_id().into())])
|
||||
.appended_with(asset_location_on_penpal)
|
||||
.unwrap();
|
||||
|
||||
// Encoded `create_asset` call to be executed in AssetHub
|
||||
let call = AssetHubPezkuwichain::create_foreign_asset_call(
|
||||
foreign_asset_at_asset_hub.clone(),
|
||||
ASSET_MIN_BALANCE,
|
||||
para_sovereign_account.clone(),
|
||||
);
|
||||
|
||||
let origin_kind = OriginKind::Xcm;
|
||||
let fee_amount = ASSET_HUB_PEZKUWICHAIN_ED * 1000000;
|
||||
let system_asset = (Parent, fee_amount).into();
|
||||
|
||||
let root_origin = <PenpalA as Chain>::RuntimeOrigin::root();
|
||||
let system_para_destination =
|
||||
PenpalA::sibling_location_of(AssetHubPezkuwichain::para_id()).into();
|
||||
let xcm = xcm_transact_paid_execution(
|
||||
call,
|
||||
origin_kind,
|
||||
system_asset,
|
||||
para_sovereign_account.clone(),
|
||||
);
|
||||
|
||||
// SA-of-Penpal-on-AHR needs to have balance to pay for fees and asset creation deposit
|
||||
AssetHubPezkuwichain::fund_accounts(vec![(
|
||||
para_sovereign_account.clone().into(),
|
||||
ASSET_HUB_PEZKUWICHAIN_ED * 10000000000,
|
||||
)]);
|
||||
|
||||
PenpalA::execute_with(|| {
|
||||
assert_ok!(<PenpalA as PenpalAPallet>::PezkuwiXcm::send(
|
||||
root_origin,
|
||||
bx!(system_para_destination),
|
||||
bx!(xcm),
|
||||
));
|
||||
|
||||
PenpalA::assert_xcm_pallet_sent();
|
||||
});
|
||||
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
AssetHubPezkuwichain::assert_xcmp_queue_success(None);
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
// Burned the fee
|
||||
RuntimeEvent::Balances(pezpallet_balances::Event::Burned { who, amount }) => {
|
||||
who: *who == para_sovereign_account,
|
||||
amount: *amount == fee_amount,
|
||||
},
|
||||
// Foreign Asset created
|
||||
RuntimeEvent::ForeignAssets(pezpallet_assets::Event::Created { asset_id, creator, owner }) => {
|
||||
asset_id: *asset_id == foreign_asset_at_asset_hub,
|
||||
creator: *creator == para_sovereign_account.clone(),
|
||||
owner: *owner == para_sovereign_account,
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
type ForeignAssets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
|
||||
assert!(ForeignAssets::asset_exists(foreign_asset_at_asset_hub));
|
||||
});
|
||||
}
|
||||
|
||||
/// We tests two things here:
|
||||
/// - Teyrchain should be able to send XCM paying its fee at Asset Hub using sufficient asset
|
||||
/// - Teyrchain should be able to create a new Asset at Asset Hub
|
||||
#[test]
|
||||
fn send_xcm_from_para_to_asset_hub_paying_fee_with_sufficient_asset() {
|
||||
let para_sovereign_account = AssetHubPezkuwichain::sovereign_account_id_of(
|
||||
AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id()),
|
||||
);
|
||||
|
||||
// Force create and mint sufficient assets for Teyrchain's sovereign account
|
||||
AssetHubPezkuwichain::force_create_and_mint_asset(
|
||||
ASSET_ID,
|
||||
ASSET_MIN_BALANCE,
|
||||
true,
|
||||
para_sovereign_account.clone(),
|
||||
Some(Weight::from_parts(144_933_000, 3675)),
|
||||
ASSET_MIN_BALANCE * 1000000000,
|
||||
);
|
||||
|
||||
// Just a different `asset_id`` that does not exist yet
|
||||
let new_asset_id = ASSET_ID + 1;
|
||||
|
||||
// Encoded `create_asset` call to be executed in AssetHub
|
||||
let call = AssetHubPezkuwichain::create_asset_call(
|
||||
new_asset_id,
|
||||
ASSET_MIN_BALANCE,
|
||||
para_sovereign_account.clone(),
|
||||
);
|
||||
|
||||
let origin_kind = OriginKind::SovereignAccount;
|
||||
let fee_amount = ASSET_MIN_BALANCE * 1000000;
|
||||
let asset =
|
||||
([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())], fee_amount).into();
|
||||
let asset_location =
|
||||
Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())]);
|
||||
|
||||
let root_origin = <PenpalA as Chain>::RuntimeOrigin::root();
|
||||
let system_para_destination =
|
||||
PenpalA::sibling_location_of(AssetHubPezkuwichain::para_id()).into();
|
||||
let xcm = xcm_transact_paid_execution(call, origin_kind, asset, para_sovereign_account.clone());
|
||||
|
||||
// SA-of-Penpal-on-AHR needs to have balance to pay for asset creation deposit
|
||||
AssetHubPezkuwichain::fund_accounts(vec![(
|
||||
para_sovereign_account.clone().into(),
|
||||
ASSET_HUB_PEZKUWICHAIN_ED * 10000000000,
|
||||
)]);
|
||||
|
||||
create_pool_with_roc_on!(
|
||||
AssetHubPezkuwichain,
|
||||
asset_location,
|
||||
false,
|
||||
para_sovereign_account.clone(),
|
||||
9_000_000_000_000_000,
|
||||
9_000_000_000_000
|
||||
);
|
||||
|
||||
PenpalA::execute_with(|| {
|
||||
assert_ok!(<PenpalA as PenpalAPallet>::PezkuwiXcm::send(
|
||||
root_origin,
|
||||
bx!(system_para_destination),
|
||||
bx!(xcm),
|
||||
));
|
||||
|
||||
PenpalA::assert_xcm_pallet_sent();
|
||||
});
|
||||
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
AssetHubPezkuwichain::assert_xcmp_queue_success(None);
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
// Burned the fee
|
||||
RuntimeEvent::Assets(pezpallet_assets::Event::Burned { asset_id, owner, balance }) => {
|
||||
asset_id: *asset_id == ASSET_ID,
|
||||
owner: *owner == para_sovereign_account,
|
||||
balance: *balance == fee_amount,
|
||||
},
|
||||
// Asset created
|
||||
RuntimeEvent::Assets(pezpallet_assets::Event::Created { asset_id, creator, owner }) => {
|
||||
asset_id: *asset_id == new_asset_id,
|
||||
creator: *creator == para_sovereign_account.clone(),
|
||||
owner: *owner == para_sovereign_account,
|
||||
},
|
||||
]
|
||||
);
|
||||
});
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
// 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::imports::*;
|
||||
|
||||
#[test]
|
||||
fn relay_sets_system_para_xcm_supported_version() {
|
||||
// Init tests variables
|
||||
let sudo_origin = <Pezkuwichain as Chain>::RuntimeOrigin::root();
|
||||
let system_para_destination: Location =
|
||||
Pezkuwichain::child_location_of(AssetHubPezkuwichain::para_id());
|
||||
|
||||
// Relay Chain sets supported version for Asset Teyrchain
|
||||
Pezkuwichain::execute_with(|| {
|
||||
assert_ok!(<Pezkuwichain as PezkuwichainPallet>::XcmPallet::force_xcm_version(
|
||||
sudo_origin,
|
||||
bx!(system_para_destination.clone()),
|
||||
XCM_V3
|
||||
));
|
||||
|
||||
type RuntimeEvent = <Pezkuwichain as Chain>::RuntimeEvent;
|
||||
|
||||
assert_expected_events!(
|
||||
Pezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::XcmPallet(pezpallet_xcm::Event::SupportedVersionChanged {
|
||||
location,
|
||||
version: XCM_V3
|
||||
}) => { location: *location == system_para_destination, },
|
||||
]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn system_para_sets_relay_xcm_supported_version() {
|
||||
// Init test variables
|
||||
let parent_location = AssetHubPezkuwichain::parent_location();
|
||||
let force_xcm_version_call =
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeCall::PezkuwiXcm(pezpallet_xcm::Call::<
|
||||
<AssetHubPezkuwichain as Chain>::Runtime,
|
||||
>::force_xcm_version {
|
||||
location: bx!(parent_location.clone()),
|
||||
version: XCM_V3,
|
||||
})
|
||||
.encode()
|
||||
.into();
|
||||
|
||||
// System Teyrchain sets supported version for Relay Chain through it
|
||||
Pezkuwichain::send_unpaid_transact_to_teyrchain_as_root(
|
||||
AssetHubPezkuwichain::para_id(),
|
||||
force_xcm_version_call,
|
||||
);
|
||||
|
||||
// System Teyrchain receive the XCM message
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
|
||||
AssetHubPezkuwichain::assert_dmp_queue_complete(Some(Weight::from_parts(115_294_000, 0)));
|
||||
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::PezkuwiXcm(pezpallet_xcm::Event::SupportedVersionChanged {
|
||||
location,
|
||||
version: XCM_V3
|
||||
}) => { location: *location == parent_location, },
|
||||
]
|
||||
);
|
||||
});
|
||||
}
|
||||
+449
@@ -0,0 +1,449 @@
|
||||
// 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::imports::*;
|
||||
|
||||
#[test]
|
||||
fn swap_locally_on_chain_using_local_assets() {
|
||||
let asset_native = Box::new(Location::try_from(RelayLocation::get()).unwrap());
|
||||
let asset_one = Box::new(Location::new(
|
||||
0,
|
||||
[Junction::PalletInstance(ASSETS_PALLET_ID), Junction::GeneralIndex(ASSET_ID.into())],
|
||||
));
|
||||
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
|
||||
assert_ok!(<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Assets::create(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
AssetHubPezkuwichainSender::get()
|
||||
),
|
||||
ASSET_ID.into(),
|
||||
AssetHubPezkuwichainSender::get().into(),
|
||||
1000,
|
||||
));
|
||||
assert!(<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Assets::asset_exists(
|
||||
ASSET_ID
|
||||
));
|
||||
|
||||
assert_ok!(<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Assets::mint(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
AssetHubPezkuwichainSender::get()
|
||||
),
|
||||
ASSET_ID.into(),
|
||||
AssetHubPezkuwichainSender::get().into(),
|
||||
100_000_000_000_000,
|
||||
));
|
||||
|
||||
assert_ok!(
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::AssetConversion::create_pool(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
AssetHubPezkuwichainSender::get()
|
||||
),
|
||||
asset_native.clone(),
|
||||
asset_one.clone(),
|
||||
)
|
||||
);
|
||||
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::AssetConversion(pezpallet_asset_conversion::Event::PoolCreated { .. }) => {},
|
||||
]
|
||||
);
|
||||
|
||||
assert_ok!(
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::AssetConversion::add_liquidity(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
AssetHubPezkuwichainSender::get()
|
||||
),
|
||||
asset_native.clone(),
|
||||
asset_one.clone(),
|
||||
1_000_000_000_000,
|
||||
2_000_000_000_000,
|
||||
0,
|
||||
0,
|
||||
AssetHubPezkuwichainSender::get().into()
|
||||
)
|
||||
);
|
||||
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::AssetConversion(pezpallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { lp_token_minted: *lp_token_minted == 1414213562273, },
|
||||
]
|
||||
);
|
||||
|
||||
let path = vec![asset_native.clone(), asset_one.clone()];
|
||||
|
||||
assert_ok!(
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::AssetConversion::swap_exact_tokens_for_tokens(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(AssetHubPezkuwichainSender::get()),
|
||||
path,
|
||||
100,
|
||||
1,
|
||||
AssetHubPezkuwichainSender::get().into(),
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::AssetConversion(pezpallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. }) => {
|
||||
amount_in: *amount_in == 100,
|
||||
amount_out: *amount_out == 199,
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
assert_ok!(
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::AssetConversion::remove_liquidity(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
AssetHubPezkuwichainSender::get()
|
||||
),
|
||||
asset_native,
|
||||
asset_one,
|
||||
1414213562273 - ASSET_HUB_PEZKUWICHAIN_ED * 2, /* all but the 2 EDs can't be
|
||||
* retrieved. */
|
||||
0,
|
||||
0,
|
||||
AssetHubPezkuwichainSender::get().into(),
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn swap_locally_on_chain_using_foreign_assets() {
|
||||
let asset_native = Box::new(Location::try_from(RelayLocation::get()).unwrap());
|
||||
let asset_location_on_penpal = PenpalA::execute_with(|| {
|
||||
Location::try_from(PenpalLocalTeleportableToAssetHub::get()).unwrap()
|
||||
});
|
||||
let foreign_asset_at_asset_hub_pezkuwichain =
|
||||
Location::new(1, [Junction::Teyrchain(PenpalA::para_id().into())])
|
||||
.appended_with(asset_location_on_penpal)
|
||||
.unwrap();
|
||||
|
||||
let penpal_as_seen_by_ah = AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id());
|
||||
let sov_penpal_on_ahr = AssetHubPezkuwichain::sovereign_account_id_of(penpal_as_seen_by_ah);
|
||||
AssetHubPezkuwichain::fund_accounts(vec![
|
||||
// An account to swap dot for something else.
|
||||
(AssetHubPezkuwichainSender::get().into(), 5_000_000 * ASSET_HUB_PEZKUWICHAIN_ED),
|
||||
// Penpal's sovereign account in AH should have some balance
|
||||
(sov_penpal_on_ahr.clone().into(), 100_000_000 * ASSET_HUB_PEZKUWICHAIN_ED),
|
||||
]);
|
||||
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
// 0: No need to create foreign asset as it exists in genesis.
|
||||
//
|
||||
// 1: Mint foreign asset on asset_hub_pezkuwichain:
|
||||
//
|
||||
// (While it might be nice to use batch,
|
||||
// currently that's disabled due to safe call filters.)
|
||||
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
// 1. Mint foreign asset (in reality this should be a teleport or some such)
|
||||
assert_ok!(<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets::mint(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
sov_penpal_on_ahr.clone().into()
|
||||
),
|
||||
foreign_asset_at_asset_hub_pezkuwichain.clone(),
|
||||
sov_penpal_on_ahr.clone().into(),
|
||||
ASSET_HUB_PEZKUWICHAIN_ED * 3_000_000_000_000,
|
||||
));
|
||||
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::ForeignAssets(pezpallet_assets::Event::Issued { .. }) => {},
|
||||
]
|
||||
);
|
||||
|
||||
// 2. Create pool:
|
||||
assert_ok!(
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::AssetConversion::create_pool(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
AssetHubPezkuwichainSender::get()
|
||||
),
|
||||
asset_native.clone(),
|
||||
Box::new(foreign_asset_at_asset_hub_pezkuwichain.clone()),
|
||||
)
|
||||
);
|
||||
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::AssetConversion(pezpallet_asset_conversion::Event::PoolCreated { .. }) => {},
|
||||
]
|
||||
);
|
||||
|
||||
// 3. Add liquidity:
|
||||
assert_ok!(
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::AssetConversion::add_liquidity(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()),
|
||||
asset_native.clone(),
|
||||
Box::new(foreign_asset_at_asset_hub_pezkuwichain.clone()),
|
||||
1_000_000_000_000,
|
||||
2_000_000_000_000,
|
||||
0,
|
||||
0,
|
||||
sov_penpal_on_ahr.clone().into()
|
||||
)
|
||||
);
|
||||
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::AssetConversion(pezpallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => {
|
||||
lp_token_minted: *lp_token_minted == 1414213562273,
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// 4. Swap!
|
||||
let path =
|
||||
vec![asset_native.clone(), Box::new(foreign_asset_at_asset_hub_pezkuwichain.clone())];
|
||||
|
||||
assert_ok!(
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::AssetConversion::swap_exact_tokens_for_tokens(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(AssetHubPezkuwichainSender::get()),
|
||||
path,
|
||||
100000 * ASSET_HUB_PEZKUWICHAIN_ED,
|
||||
1000 * ASSET_HUB_PEZKUWICHAIN_ED,
|
||||
AssetHubPezkuwichainSender::get().into(),
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::AssetConversion(pezpallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. },) => {
|
||||
amount_in: *amount_in == 333333300000,
|
||||
amount_out: *amount_out == 498874118173,
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// 5. Remove liquidity
|
||||
assert_ok!(
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::AssetConversion::remove_liquidity(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()),
|
||||
asset_native.clone(),
|
||||
Box::new(foreign_asset_at_asset_hub_pezkuwichain.clone()),
|
||||
1414213562273 - ASSET_HUB_PEZKUWICHAIN_ED * 2, /* all but the 2 EDs can't be
|
||||
* retrieved. */
|
||||
0,
|
||||
0,
|
||||
sov_penpal_on_ahr.clone().into(),
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_create_pool_from_pool_assets() {
|
||||
let asset_native = RelayLocation::get();
|
||||
let mut asset_one = ahr_xcm_config::PoolAssetsPalletLocation::get();
|
||||
asset_one.append_with(GeneralIndex(ASSET_ID.into())).expect("pool assets");
|
||||
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
let pool_owner_account_id = AssetHubPezkuwichainAssetConversionOrigin::get();
|
||||
|
||||
assert_ok!(<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::PoolAssets::create(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(pool_owner_account_id.clone()),
|
||||
ASSET_ID.into(),
|
||||
pool_owner_account_id.clone().into(),
|
||||
1000,
|
||||
));
|
||||
assert!(<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::PoolAssets::asset_exists(
|
||||
ASSET_ID
|
||||
));
|
||||
|
||||
assert_ok!(<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::PoolAssets::mint(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(pool_owner_account_id),
|
||||
ASSET_ID.into(),
|
||||
AssetHubPezkuwichainSender::get().into(),
|
||||
3_000_000_000_000,
|
||||
));
|
||||
|
||||
assert_matches::assert_matches!(
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::AssetConversion::create_pool(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(AssetHubPezkuwichainSender::get()),
|
||||
Box::new(Location::try_from(asset_native).unwrap()),
|
||||
Box::new(Location::try_from(asset_one).unwrap()),
|
||||
),
|
||||
Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("Unknown"))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pay_xcm_fee_with_some_asset_swapped_for_native() {
|
||||
let asset_native = Location::try_from(RelayLocation::get()).unwrap();
|
||||
let asset_one = Location {
|
||||
parents: 0,
|
||||
interior: [
|
||||
Junction::PalletInstance(ASSETS_PALLET_ID),
|
||||
Junction::GeneralIndex(ASSET_ID.into()),
|
||||
]
|
||||
.into(),
|
||||
};
|
||||
let penpal = AssetHubPezkuwichain::sovereign_account_id_of(
|
||||
AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id()),
|
||||
);
|
||||
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
|
||||
// set up pool with ASSET_ID <> NATIVE pair
|
||||
assert_ok!(<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Assets::create(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
AssetHubPezkuwichainSender::get()
|
||||
),
|
||||
ASSET_ID.into(),
|
||||
AssetHubPezkuwichainSender::get().into(),
|
||||
ASSET_MIN_BALANCE,
|
||||
));
|
||||
assert!(<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Assets::asset_exists(
|
||||
ASSET_ID
|
||||
));
|
||||
|
||||
assert_ok!(<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Assets::mint(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
AssetHubPezkuwichainSender::get()
|
||||
),
|
||||
ASSET_ID.into(),
|
||||
AssetHubPezkuwichainSender::get().into(),
|
||||
3_000_000_000_000,
|
||||
));
|
||||
|
||||
assert_ok!(
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::AssetConversion::create_pool(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
AssetHubPezkuwichainSender::get()
|
||||
),
|
||||
Box::new(asset_native.clone()),
|
||||
Box::new(asset_one.clone()),
|
||||
)
|
||||
);
|
||||
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::AssetConversion(pezpallet_asset_conversion::Event::PoolCreated { .. }) => {},
|
||||
]
|
||||
);
|
||||
|
||||
assert_ok!(
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::AssetConversion::add_liquidity(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
AssetHubPezkuwichainSender::get()
|
||||
),
|
||||
Box::new(asset_native),
|
||||
Box::new(asset_one),
|
||||
1_000_000_000_000,
|
||||
2_000_000_000_000,
|
||||
0,
|
||||
0,
|
||||
AssetHubPezkuwichainSender::get().into()
|
||||
)
|
||||
);
|
||||
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::AssetConversion(pezpallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { lp_token_minted: *lp_token_minted == 1414213562273, },
|
||||
]
|
||||
);
|
||||
|
||||
// ensure `penpal` sovereign account has no native tokens and mint some `ASSET_ID`
|
||||
assert_eq!(
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Balances::free_balance(
|
||||
penpal.clone()
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
assert_ok!(<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Assets::touch_other(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
AssetHubPezkuwichainSender::get()
|
||||
),
|
||||
ASSET_ID.into(),
|
||||
penpal.clone().into(),
|
||||
));
|
||||
|
||||
assert_ok!(<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Assets::mint(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
AssetHubPezkuwichainSender::get()
|
||||
),
|
||||
ASSET_ID.into(),
|
||||
penpal.clone().into(),
|
||||
10_000_000_000_000,
|
||||
));
|
||||
});
|
||||
|
||||
PenpalA::execute_with(|| {
|
||||
// send xcm transact from `penpal` account while paying with `ASSET_ID` tokens on
|
||||
// `AssetHubPezkuwichain`
|
||||
let call = <AssetHubPezkuwichain as Chain>::RuntimeCall::System(pezframe_system::Call::<
|
||||
<AssetHubPezkuwichain as Chain>::Runtime,
|
||||
>::remark {
|
||||
remark: vec![],
|
||||
})
|
||||
.encode()
|
||||
.into();
|
||||
|
||||
let penpal_root = <PenpalA as Chain>::RuntimeOrigin::root();
|
||||
let fee_amount = 4_000_000_000_000u128;
|
||||
let asset_one =
|
||||
([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())], fee_amount).into();
|
||||
let asset_hub_location =
|
||||
PenpalA::sibling_location_of(AssetHubPezkuwichain::para_id()).into();
|
||||
let xcm = xcm_transact_paid_execution(
|
||||
call,
|
||||
OriginKind::SovereignAccount,
|
||||
asset_one,
|
||||
penpal.clone(),
|
||||
);
|
||||
|
||||
assert_ok!(<PenpalA as PenpalAPallet>::PezkuwiXcm::send(
|
||||
penpal_root,
|
||||
bx!(asset_hub_location),
|
||||
bx!(xcm),
|
||||
));
|
||||
|
||||
PenpalA::assert_xcm_pallet_sent();
|
||||
});
|
||||
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
|
||||
AssetHubPezkuwichain::assert_xcmp_queue_success(None);
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::AssetConversion(pezpallet_asset_conversion::Event::SwapCreditExecuted { .. },) => {},
|
||||
RuntimeEvent::MessageQueue(pezpallet_message_queue::Event::Processed { success: true,.. }) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xcm_fee_querying_apis_work() {
|
||||
test_xcm_fee_querying_apis_work_for_asset_hub!(AssetHubPezkuwichain);
|
||||
}
|
||||
+643
@@ -0,0 +1,643 @@
|
||||
// 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::imports::*;
|
||||
|
||||
fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) {
|
||||
Pezkuwichain::assert_ump_queue_processed(
|
||||
false,
|
||||
Some(AssetHubPezkuwichain::para_id()),
|
||||
Some(Weight::from_parts(157_718_000, 3_593)),
|
||||
);
|
||||
}
|
||||
|
||||
fn para_origin_assertions(t: SystemParaToRelayTest) {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
|
||||
AssetHubPezkuwichain::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(
|
||||
730_053_000,
|
||||
4_000,
|
||||
)));
|
||||
|
||||
AssetHubPezkuwichain::assert_teyrchain_system_ump_sent();
|
||||
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
// Amount is withdrawn from Sender's account
|
||||
RuntimeEvent::Balances(pezpallet_balances::Event::Burned { who, amount }) => {
|
||||
who: *who == t.sender.account_id,
|
||||
amount: *amount == t.args.amount,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) {
|
||||
type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
|
||||
let system_para_native_asset_location = RelayLocation::get();
|
||||
let expected_asset_id = t.args.asset_id.unwrap();
|
||||
let (_, expected_asset_amount) = non_fee_asset(&t.args.assets, &t.args.fee_asset_id).unwrap();
|
||||
|
||||
PenpalA::assert_xcm_pallet_attempted_complete(None);
|
||||
assert_expected_events!(
|
||||
PenpalA,
|
||||
vec![
|
||||
RuntimeEvent::ForeignAssets(
|
||||
pezpallet_assets::Event::Burned { asset_id, owner, .. }
|
||||
) => {
|
||||
asset_id: *asset_id == system_para_native_asset_location,
|
||||
owner: *owner == t.sender.account_id,
|
||||
},
|
||||
RuntimeEvent::Assets(pezpallet_assets::Event::Burned { asset_id, owner, balance }) => {
|
||||
asset_id: *asset_id == expected_asset_id,
|
||||
owner: *owner == t.sender.account_id,
|
||||
balance: *balance == expected_asset_amount,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
let sov_penpal_on_ahr = AssetHubPezkuwichain::sovereign_account_id_of(
|
||||
AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id()),
|
||||
);
|
||||
let (_, expected_foreign_asset_amount) =
|
||||
non_fee_asset(&t.args.assets, &t.args.fee_asset_id).unwrap();
|
||||
let (_, fee_asset_amount) = fee_asset(&t.args.assets, &t.args.fee_asset_id).unwrap();
|
||||
|
||||
AssetHubPezkuwichain::assert_xcmp_queue_success(None);
|
||||
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
// native asset reserve transfer for paying fees, withdrawn from Penpal's sov account
|
||||
RuntimeEvent::Balances(
|
||||
pezpallet_balances::Event::Burned { who, amount }
|
||||
) => {
|
||||
who: *who == sov_penpal_on_ahr.clone().into(),
|
||||
amount: *amount == fee_asset_amount,
|
||||
},
|
||||
RuntimeEvent::Balances(pezpallet_balances::Event::Minted { who, .. }) => {
|
||||
who: *who == t.receiver.account_id,
|
||||
},
|
||||
RuntimeEvent::ForeignAssets(pezpallet_assets::Event::Issued { asset_id, owner, amount }) => {
|
||||
asset_id: *asset_id == PenpalATeleportableAssetLocation::get(),
|
||||
owner: *owner == t.receiver.account_id,
|
||||
amount: *amount == expected_foreign_asset_amount,
|
||||
},
|
||||
RuntimeEvent::Balances(pezpallet_balances::Event::Deposit { .. }) => {},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
AssetHubPezkuwichain::assert_xcm_pallet_attempted_complete(None);
|
||||
let (expected_foreign_asset_id, expected_foreign_asset_amount) =
|
||||
non_fee_asset(&t.args.assets, &t.args.fee_asset_id).unwrap();
|
||||
let (_, fee_asset_amount) = fee_asset(&t.args.assets, &t.args.fee_asset_id).unwrap();
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
// native asset used for fees is transferred to Teyrchain's Sovereign account as reserve
|
||||
RuntimeEvent::Balances(
|
||||
pezpallet_balances::Event::Transfer { from, to, amount }
|
||||
) => {
|
||||
from: *from == t.sender.account_id,
|
||||
to: *to == AssetHubPezkuwichain::sovereign_account_id_of(
|
||||
t.args.dest.clone()
|
||||
),
|
||||
amount: *amount == fee_asset_amount,
|
||||
},
|
||||
// foreign asset is burned locally as part of teleportation
|
||||
RuntimeEvent::ForeignAssets(pezpallet_assets::Event::Burned { asset_id, owner, balance }) => {
|
||||
asset_id: *asset_id == expected_foreign_asset_id,
|
||||
owner: *owner == t.sender.account_id,
|
||||
balance: *balance == expected_foreign_asset_amount,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) {
|
||||
type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
|
||||
let expected_asset_id = t.args.asset_id.unwrap();
|
||||
let (_, expected_asset_amount) = non_fee_asset(&t.args.assets, &t.args.fee_asset_id).unwrap();
|
||||
let checking_account = <PenpalA as PenpalAPallet>::PezkuwiXcm::check_account();
|
||||
let system_para_native_asset_location = RelayLocation::get();
|
||||
|
||||
PenpalA::assert_xcmp_queue_success(None);
|
||||
|
||||
assert_expected_events!(
|
||||
PenpalA,
|
||||
vec![
|
||||
// checking account burns local asset as part of incoming teleport
|
||||
RuntimeEvent::Assets(pezpallet_assets::Event::Burned { asset_id, owner, balance }) => {
|
||||
asset_id: *asset_id == expected_asset_id,
|
||||
owner: *owner == checking_account,
|
||||
balance: *balance == expected_asset_amount,
|
||||
},
|
||||
// local asset is teleported into account of receiver
|
||||
RuntimeEvent::Assets(pezpallet_assets::Event::Issued { asset_id, owner, amount }) => {
|
||||
asset_id: *asset_id == expected_asset_id,
|
||||
owner: *owner == t.receiver.account_id,
|
||||
amount: *amount == expected_asset_amount,
|
||||
},
|
||||
// native asset for fee is deposited to receiver
|
||||
RuntimeEvent::ForeignAssets(pezpallet_assets::Event::Issued { asset_id, owner, .. }) => {
|
||||
asset_id: *asset_id == system_para_native_asset_location,
|
||||
owner: *owner == t.receiver.account_id,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult {
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::PezkuwiXcm::limited_teleport_assets(
|
||||
t.signed_origin,
|
||||
bx!(t.args.dest.into()),
|
||||
bx!(t.args.beneficiary.into()),
|
||||
bx!(t.args.assets.into()),
|
||||
bx!(t.args.fee_asset_id.into()),
|
||||
t.args.weight_limit,
|
||||
)
|
||||
}
|
||||
|
||||
fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult {
|
||||
<PenpalA as PenpalAPallet>::PezkuwiXcm::transfer_assets_using_type_and_then(
|
||||
t.signed_origin,
|
||||
bx!(t.args.dest.into()),
|
||||
bx!(t.args.assets.into()),
|
||||
bx!(TransferType::Teleport),
|
||||
bx!(t.args.fee_asset_id.into()),
|
||||
bx!(TransferType::DestinationReserve),
|
||||
bx!(VersionedXcm::from(
|
||||
Xcm::<()>::builder_unsafe()
|
||||
.deposit_asset(AllCounted(2), t.args.beneficiary)
|
||||
.build()
|
||||
)),
|
||||
t.args.weight_limit,
|
||||
)
|
||||
}
|
||||
|
||||
fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult {
|
||||
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::PezkuwiXcm::transfer_assets_using_type_and_then(
|
||||
t.signed_origin,
|
||||
bx!(t.args.dest.into()),
|
||||
bx!(t.args.assets.into()),
|
||||
bx!(TransferType::Teleport),
|
||||
bx!(t.args.fee_asset_id.into()),
|
||||
bx!(TransferType::LocalReserve),
|
||||
bx!(VersionedXcm::from(
|
||||
Xcm::<()>::builder_unsafe()
|
||||
.deposit_asset(AllCounted(2), t.args.beneficiary)
|
||||
.build()
|
||||
)),
|
||||
t.args.weight_limit,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn teleport_via_limited_teleport_assets_to_other_system_teyrchains_works() {
|
||||
let amount = ASSET_HUB_PEZKUWICHAIN_ED * 100;
|
||||
let native_asset: Assets = (Parent, amount).into();
|
||||
let fee_asset_id: AssetId = Parent.into();
|
||||
|
||||
test_teyrchain_is_trusted_teleporter!(
|
||||
AssetHubPezkuwichain, // Origin
|
||||
vec![BridgeHubPezkuwichain], // Destinations
|
||||
(native_asset, amount),
|
||||
fee_asset_id,
|
||||
limited_teleport_assets
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn teleport_via_transfer_assets_to_other_system_teyrchains_works() {
|
||||
let amount = ASSET_HUB_PEZKUWICHAIN_ED * 100;
|
||||
let native_asset: Assets = (Parent, amount).into();
|
||||
let fee_asset_id: AssetId = Parent.into();
|
||||
|
||||
test_teyrchain_is_trusted_teleporter!(
|
||||
AssetHubPezkuwichain, // Origin
|
||||
vec![BridgeHubPezkuwichain], // Destinations
|
||||
(native_asset, amount),
|
||||
fee_asset_id,
|
||||
transfer_assets
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn teleport_via_limited_teleport_assets_from_and_to_relay() {
|
||||
let amount = PEZKUWICHAIN_ED * 100;
|
||||
|
||||
test_relay_is_trusted_teleporter!(
|
||||
Pezkuwichain,
|
||||
vec![AssetHubPezkuwichain],
|
||||
amount,
|
||||
limited_teleport_assets
|
||||
);
|
||||
|
||||
test_teyrchain_is_trusted_teleporter_for_relay!(
|
||||
AssetHubPezkuwichain,
|
||||
Pezkuwichain,
|
||||
amount,
|
||||
limited_teleport_assets
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn teleport_via_transfer_assets_from_and_to_relay() {
|
||||
let amount = PEZKUWICHAIN_ED * 100;
|
||||
|
||||
test_relay_is_trusted_teleporter!(
|
||||
Pezkuwichain,
|
||||
vec![AssetHubPezkuwichain],
|
||||
amount,
|
||||
transfer_assets
|
||||
);
|
||||
|
||||
test_teyrchain_is_trusted_teleporter_for_relay!(
|
||||
AssetHubPezkuwichain,
|
||||
Pezkuwichain,
|
||||
amount,
|
||||
transfer_assets
|
||||
);
|
||||
}
|
||||
|
||||
/// Limited Teleport of native asset from System Teyrchain to Relay Chain
|
||||
/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount`
|
||||
#[test]
|
||||
fn limited_teleport_native_assets_from_system_para_to_relay_fails() {
|
||||
// Init values for Relay Chain
|
||||
let amount_to_send: Balance = ASSET_HUB_PEZKUWICHAIN_ED * 1000;
|
||||
let destination = AssetHubPezkuwichain::parent_location().into();
|
||||
let beneficiary_id = PezkuwichainReceiver::get().into();
|
||||
let assets = (Parent, amount_to_send).into();
|
||||
let fee_asset_id: AssetId = Parent.into();
|
||||
|
||||
let test_args = TestContext {
|
||||
sender: AssetHubPezkuwichainSender::get(),
|
||||
receiver: PezkuwichainReceiver::get(),
|
||||
args: TestArgs::new_para(
|
||||
destination,
|
||||
beneficiary_id,
|
||||
amount_to_send,
|
||||
assets,
|
||||
None,
|
||||
fee_asset_id.clone(),
|
||||
),
|
||||
};
|
||||
|
||||
let mut test = SystemParaToRelayTest::new(test_args);
|
||||
|
||||
let sender_balance_before = test.sender.balance;
|
||||
let receiver_balance_before = test.receiver.balance;
|
||||
|
||||
test.set_assertion::<AssetHubPezkuwichain>(para_origin_assertions);
|
||||
test.set_assertion::<Pezkuwichain>(relay_dest_assertions_fail);
|
||||
test.set_dispatchable::<AssetHubPezkuwichain>(system_para_limited_teleport_assets);
|
||||
test.assert();
|
||||
|
||||
let sender_balance_after = test.sender.balance;
|
||||
let receiver_balance_after = test.receiver.balance;
|
||||
|
||||
let delivery_fees = AssetHubPezkuwichain::execute_with(|| {
|
||||
xcm_helpers::teleport_assets_delivery_fees::<
|
||||
<AssetHubPezkuwichainXcmConfig as xcm_executor::Config>::XcmSender,
|
||||
>(
|
||||
test.args.assets.clone(),
|
||||
fee_asset_id,
|
||||
test.args.weight_limit,
|
||||
test.args.beneficiary,
|
||||
test.args.dest,
|
||||
)
|
||||
});
|
||||
|
||||
// Sender's balance is reduced
|
||||
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
|
||||
// Receiver's balance does not change
|
||||
assert_eq!(receiver_balance_after, receiver_balance_before);
|
||||
}
|
||||
|
||||
/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets while paying
|
||||
/// fees using (reserve transferred) native asset.
|
||||
pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt(
|
||||
para_to_ah_dispatchable: fn(ParaToSystemParaTest) -> DispatchResult,
|
||||
ah_to_para_dispatchable: fn(SystemParaToParaTest) -> DispatchResult,
|
||||
) {
|
||||
// Init values for Teyrchain
|
||||
let fee_amount_to_send: Balance = ASSET_HUB_PEZKUWICHAIN_ED * 10000;
|
||||
let asset_location_on_penpal =
|
||||
PenpalA::execute_with(|| PenpalLocalTeleportableToAssetHub::get());
|
||||
let asset_id_on_penpal = match asset_location_on_penpal.last() {
|
||||
Some(Junction::GeneralIndex(id)) => *id as u32,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let asset_amount_to_send = ASSET_HUB_PEZKUWICHAIN_ED * 1000;
|
||||
|
||||
let asset_owner = PenpalAssetOwner::get();
|
||||
let system_para_native_asset_location = RelayLocation::get();
|
||||
let sender = PenpalASender::get();
|
||||
let penpal_check_account = <PenpalA as PenpalAPallet>::PezkuwiXcm::check_account();
|
||||
let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubPezkuwichain::para_id());
|
||||
let penpal_assets: Assets = vec![
|
||||
(Parent, fee_amount_to_send).into(),
|
||||
(asset_location_on_penpal.clone(), asset_amount_to_send).into(),
|
||||
]
|
||||
.into();
|
||||
let fee_asset_id: AssetId = Parent.into();
|
||||
|
||||
// fund Teyrchain's sender account
|
||||
PenpalA::mint_foreign_asset(
|
||||
<PenpalA as Chain>::RuntimeOrigin::signed(asset_owner.clone()),
|
||||
system_para_native_asset_location.clone(),
|
||||
sender.clone(),
|
||||
fee_amount_to_send * 2,
|
||||
);
|
||||
// No need to create the asset (only mint) as it exists in genesis.
|
||||
PenpalA::mint_asset(
|
||||
<PenpalA as Chain>::RuntimeOrigin::signed(asset_owner.clone()),
|
||||
asset_id_on_penpal,
|
||||
sender.clone(),
|
||||
asset_amount_to_send,
|
||||
);
|
||||
// fund Teyrchain's check account to be able to teleport
|
||||
PenpalA::fund_accounts(vec![(
|
||||
penpal_check_account.clone().into(),
|
||||
ASSET_HUB_PEZKUWICHAIN_ED * 1000,
|
||||
)]);
|
||||
|
||||
// prefund SA of Penpal on AssetHub with enough native tokens to pay for fees
|
||||
let penpal_as_seen_by_ah = AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id());
|
||||
let sov_penpal_on_ah = AssetHubPezkuwichain::sovereign_account_id_of(penpal_as_seen_by_ah);
|
||||
AssetHubPezkuwichain::fund_accounts(vec![(
|
||||
sov_penpal_on_ah.clone().into(),
|
||||
ASSET_HUB_PEZKUWICHAIN_ED * 100_000_000_000,
|
||||
)]);
|
||||
|
||||
// Init values for System Teyrchain
|
||||
let foreign_asset_at_asset_hub_pezkuwichain =
|
||||
Location::new(1, [Junction::Teyrchain(PenpalA::para_id().into())])
|
||||
.appended_with(asset_location_on_penpal)
|
||||
.unwrap();
|
||||
let penpal_to_ah_beneficiary_id = AssetHubPezkuwichainReceiver::get();
|
||||
|
||||
// Penpal to AH test args
|
||||
let penpal_to_ah_test_args = TestContext {
|
||||
sender: PenpalASender::get(),
|
||||
receiver: AssetHubPezkuwichainReceiver::get(),
|
||||
args: TestArgs::new_para(
|
||||
ah_as_seen_by_penpal,
|
||||
penpal_to_ah_beneficiary_id,
|
||||
asset_amount_to_send,
|
||||
penpal_assets,
|
||||
Some(asset_id_on_penpal),
|
||||
fee_asset_id,
|
||||
),
|
||||
};
|
||||
let mut penpal_to_ah = ParaToSystemParaTest::new(penpal_to_ah_test_args);
|
||||
let penpal_sender_balance_before = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(
|
||||
system_para_native_asset_location.clone(),
|
||||
&PenpalASender::get(),
|
||||
)
|
||||
});
|
||||
|
||||
let ah_receiver_balance_before = penpal_to_ah.receiver.balance;
|
||||
|
||||
let penpal_sender_assets_before = PenpalA::execute_with(|| {
|
||||
type Assets = <PenpalA as PenpalAPallet>::Assets;
|
||||
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalASender::get())
|
||||
});
|
||||
let ah_receiver_assets_before = AssetHubPezkuwichain::execute_with(|| {
|
||||
type Assets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
|
||||
<Assets as Inspect<_>>::balance(
|
||||
foreign_asset_at_asset_hub_pezkuwichain.clone().try_into().unwrap(),
|
||||
&AssetHubPezkuwichainReceiver::get(),
|
||||
)
|
||||
});
|
||||
|
||||
penpal_to_ah.set_assertion::<PenpalA>(penpal_to_ah_foreign_assets_sender_assertions);
|
||||
penpal_to_ah
|
||||
.set_assertion::<AssetHubPezkuwichain>(penpal_to_ah_foreign_assets_receiver_assertions);
|
||||
penpal_to_ah.set_dispatchable::<PenpalA>(para_to_ah_dispatchable);
|
||||
penpal_to_ah.assert();
|
||||
|
||||
let penpal_sender_balance_after = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(
|
||||
system_para_native_asset_location.clone(),
|
||||
&PenpalASender::get(),
|
||||
)
|
||||
});
|
||||
|
||||
let ah_receiver_balance_after = penpal_to_ah.receiver.balance;
|
||||
|
||||
let penpal_sender_assets_after = PenpalA::execute_with(|| {
|
||||
type Assets = <PenpalA as PenpalAPallet>::Assets;
|
||||
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalASender::get())
|
||||
});
|
||||
let ah_receiver_assets_after = AssetHubPezkuwichain::execute_with(|| {
|
||||
type Assets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
|
||||
<Assets as Inspect<_>>::balance(
|
||||
foreign_asset_at_asset_hub_pezkuwichain.clone().try_into().unwrap(),
|
||||
&AssetHubPezkuwichainReceiver::get(),
|
||||
)
|
||||
});
|
||||
|
||||
// Sender's balance is reduced
|
||||
assert!(penpal_sender_balance_after < penpal_sender_balance_before);
|
||||
// Receiver's balance is increased
|
||||
assert!(ah_receiver_balance_after > ah_receiver_balance_before);
|
||||
// Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`;
|
||||
// `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but
|
||||
// should be non-zero
|
||||
assert!(ah_receiver_balance_after < ah_receiver_balance_before + fee_amount_to_send);
|
||||
|
||||
// Sender's balance is reduced by exact amount
|
||||
assert_eq!(penpal_sender_assets_before - asset_amount_to_send, penpal_sender_assets_after);
|
||||
// Receiver's balance is increased by exact amount
|
||||
assert_eq!(ah_receiver_assets_after, ah_receiver_assets_before + asset_amount_to_send);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Now test transferring foreign assets back from AssetHub to Penpal //
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Move funds on AH from AHReceiver to AHSender
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
type ForeignAssets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
|
||||
assert_ok!(ForeignAssets::transfer(
|
||||
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
AssetHubPezkuwichainReceiver::get()
|
||||
),
|
||||
foreign_asset_at_asset_hub_pezkuwichain.clone().try_into().unwrap(),
|
||||
AssetHubPezkuwichainSender::get().into(),
|
||||
asset_amount_to_send,
|
||||
));
|
||||
});
|
||||
|
||||
let ah_to_penpal_beneficiary_id = PenpalAReceiver::get();
|
||||
let penpal_as_seen_by_ah = AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id());
|
||||
let ah_assets: Assets = vec![
|
||||
(Parent, fee_amount_to_send).into(),
|
||||
(foreign_asset_at_asset_hub_pezkuwichain.clone(), asset_amount_to_send).into(),
|
||||
]
|
||||
.into();
|
||||
let fee_asset_id: AssetId = Parent.into();
|
||||
|
||||
// AH to Penpal test args
|
||||
let ah_to_penpal_test_args = TestContext {
|
||||
sender: AssetHubPezkuwichainSender::get(),
|
||||
receiver: PenpalAReceiver::get(),
|
||||
args: TestArgs::new_para(
|
||||
penpal_as_seen_by_ah,
|
||||
ah_to_penpal_beneficiary_id,
|
||||
asset_amount_to_send,
|
||||
ah_assets,
|
||||
Some(asset_id_on_penpal),
|
||||
fee_asset_id,
|
||||
),
|
||||
};
|
||||
|
||||
let mut ah_to_penpal = SystemParaToParaTest::new(ah_to_penpal_test_args);
|
||||
|
||||
let ah_sender_balance_before = ah_to_penpal.sender.balance;
|
||||
let penpal_receiver_balance_before = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(
|
||||
system_para_native_asset_location.clone(),
|
||||
&PenpalAReceiver::get(),
|
||||
)
|
||||
});
|
||||
|
||||
let ah_sender_assets_before = AssetHubPezkuwichain::execute_with(|| {
|
||||
type ForeignAssets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(
|
||||
foreign_asset_at_asset_hub_pezkuwichain.clone().try_into().unwrap(),
|
||||
&AssetHubPezkuwichainSender::get(),
|
||||
)
|
||||
});
|
||||
let penpal_receiver_assets_before = PenpalA::execute_with(|| {
|
||||
type Assets = <PenpalA as PenpalAPallet>::Assets;
|
||||
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalAReceiver::get())
|
||||
});
|
||||
|
||||
ah_to_penpal
|
||||
.set_assertion::<AssetHubPezkuwichain>(ah_to_penpal_foreign_assets_sender_assertions);
|
||||
ah_to_penpal.set_assertion::<PenpalA>(ah_to_penpal_foreign_assets_receiver_assertions);
|
||||
ah_to_penpal.set_dispatchable::<AssetHubPezkuwichain>(ah_to_para_dispatchable);
|
||||
ah_to_penpal.assert();
|
||||
|
||||
let ah_sender_balance_after = ah_to_penpal.sender.balance;
|
||||
let penpal_receiver_balance_after = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(
|
||||
system_para_native_asset_location,
|
||||
&PenpalAReceiver::get(),
|
||||
)
|
||||
});
|
||||
|
||||
let ah_sender_assets_after = AssetHubPezkuwichain::execute_with(|| {
|
||||
type ForeignAssets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(
|
||||
foreign_asset_at_asset_hub_pezkuwichain.try_into().unwrap(),
|
||||
&AssetHubPezkuwichainSender::get(),
|
||||
)
|
||||
});
|
||||
let penpal_receiver_assets_after = PenpalA::execute_with(|| {
|
||||
type Assets = <PenpalA as PenpalAPallet>::Assets;
|
||||
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalAReceiver::get())
|
||||
});
|
||||
|
||||
// Sender's balance is reduced
|
||||
assert!(ah_sender_balance_after < ah_sender_balance_before);
|
||||
// Receiver's balance is increased
|
||||
assert!(penpal_receiver_balance_after > penpal_receiver_balance_before);
|
||||
// Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`;
|
||||
// `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but
|
||||
// should be non-zero
|
||||
assert!(penpal_receiver_balance_after < penpal_receiver_balance_before + fee_amount_to_send);
|
||||
|
||||
// Sender's balance is reduced by exact amount
|
||||
assert_eq!(ah_sender_assets_before - asset_amount_to_send, ah_sender_assets_after);
|
||||
// Receiver's balance is increased by exact amount
|
||||
assert_eq!(penpal_receiver_assets_after, penpal_receiver_assets_before + asset_amount_to_send);
|
||||
}
|
||||
|
||||
/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets should work
|
||||
/// (using native reserve-based transfer for fees)
|
||||
#[test]
|
||||
fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() {
|
||||
do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt(
|
||||
para_to_system_para_transfer_assets,
|
||||
system_para_to_para_transfer_assets,
|
||||
);
|
||||
}
|
||||
|
||||
/// Teleport Native Asset from AssetHub to Teyrchain fails.
|
||||
#[test]
|
||||
fn teleport_to_untrusted_chain_fails() {
|
||||
// Init values for Teyrchain Origin
|
||||
let destination = AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id());
|
||||
let signed_origin = <AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(
|
||||
AssetHubPezkuwichainSender::get().into(),
|
||||
);
|
||||
let roc_to_send: Balance = PEZKUWICHAIN_ED * 10000;
|
||||
let roc_location = RelayLocation::get();
|
||||
|
||||
// Assets to send
|
||||
let assets: Vec<Asset> = vec![(roc_location.clone(), roc_to_send).into()];
|
||||
let fee_id: AssetId = roc_location.into();
|
||||
|
||||
// this should fail
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
let result = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::PezkuwiXcm::transfer_assets_using_type_and_then(
|
||||
signed_origin.clone(),
|
||||
bx!(destination.clone().into()),
|
||||
bx!(assets.clone().into()),
|
||||
bx!(TransferType::Teleport),
|
||||
bx!(fee_id.into()),
|
||||
bx!(TransferType::Teleport),
|
||||
bx!(VersionedXcm::from(Xcm::<()>::new())),
|
||||
Unlimited,
|
||||
);
|
||||
assert_err!(
|
||||
result,
|
||||
DispatchError::Module(pezsp_runtime::ModuleError {
|
||||
index: 31,
|
||||
error: [2, 0, 0, 0],
|
||||
message: Some("Filtered")
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// this should also fail
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
let xcm: Xcm<asset_hub_pezkuwichain_runtime::RuntimeCall> = Xcm(vec![
|
||||
WithdrawAsset(assets.into()),
|
||||
InitiateTeleport { assets: Wild(All), dest: destination, xcm: Xcm::<()>::new() },
|
||||
]);
|
||||
let result = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::PezkuwiXcm::execute(
|
||||
signed_origin,
|
||||
bx!(xcm::VersionedXcm::from(xcm)),
|
||||
Weight::MAX,
|
||||
);
|
||||
assert!(result.is_err());
|
||||
});
|
||||
}
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
// 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::imports::*;
|
||||
use emulated_integration_tests_common::{
|
||||
accounts::{ALICE, BOB},
|
||||
USDT_ID,
|
||||
};
|
||||
use pezframe_support::{
|
||||
dispatch::RawOrigin,
|
||||
pezsp_runtime::traits::Dispatchable,
|
||||
traits::{
|
||||
fungible::Inspect,
|
||||
fungibles::{Inspect as FungiblesInspect, Mutate},
|
||||
},
|
||||
};
|
||||
use pezkuwi_runtime_common::impls::VersionedLocatableAsset;
|
||||
use pezkuwichain_runtime_constants::currency::GRAND;
|
||||
use teyrchains_common::AccountId;
|
||||
use xcm_executor::traits::ConvertLocation;
|
||||
|
||||
// Fund Treasury account on Asset Hub from Treasury account on Relay Chain with TYRs.
|
||||
#[test]
|
||||
fn spend_roc_on_asset_hub() {
|
||||
// initial treasury balance on Asset Hub in TYRs.
|
||||
let treasury_balance = 9_000 * GRAND;
|
||||
// the balance spend on Asset Hub.
|
||||
let treasury_spend_balance = 1_000 * GRAND;
|
||||
|
||||
let init_alice_balance = AssetHubPezkuwichain::execute_with(|| {
|
||||
<<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Balances as Inspect<_>>::balance(
|
||||
&AssetHubPezkuwichain::account_id_of(ALICE),
|
||||
)
|
||||
});
|
||||
|
||||
Pezkuwichain::execute_with(|| {
|
||||
type RuntimeEvent = <Pezkuwichain as Chain>::RuntimeEvent;
|
||||
type RuntimeCall = <Pezkuwichain as Chain>::RuntimeCall;
|
||||
type Runtime = <Pezkuwichain as Chain>::Runtime;
|
||||
type Balances = <Pezkuwichain as PezkuwichainPallet>::Balances;
|
||||
type Treasury = <Pezkuwichain as PezkuwichainPallet>::Treasury;
|
||||
|
||||
// Fund Treasury account on Asset Hub with TYRs.
|
||||
|
||||
let root = <Pezkuwichain as Chain>::RuntimeOrigin::root();
|
||||
let treasury_account = Treasury::account_id();
|
||||
|
||||
// Mint assets to Treasury account on Relay Chain.
|
||||
assert_ok!(Balances::force_set_balance(
|
||||
root.clone(),
|
||||
treasury_account.clone().into(),
|
||||
treasury_balance * 2,
|
||||
));
|
||||
|
||||
Dmp::make_teyrchain_reachable(1000);
|
||||
let native_asset = Location::here();
|
||||
let asset_hub_location: Location = [Teyrchain(1000)].into();
|
||||
let treasury_location: Location = (Parent, PalletInstance(18)).into();
|
||||
|
||||
let teleport_call = RuntimeCall::Utility(pezpallet_utility::Call::<Runtime>::dispatch_as {
|
||||
as_origin: bx!(PezkuwichainOriginCaller::system(RawOrigin::Signed(treasury_account))),
|
||||
call: bx!(RuntimeCall::XcmPallet(pezpallet_xcm::Call::<Runtime>::teleport_assets {
|
||||
dest: bx!(VersionedLocation::from(asset_hub_location.clone())),
|
||||
beneficiary: bx!(VersionedLocation::from(treasury_location)),
|
||||
assets: bx!(VersionedAssets::from(Assets::from(Asset {
|
||||
id: native_asset.clone().into(),
|
||||
fun: treasury_balance.into()
|
||||
}))),
|
||||
fee_asset_id: bx!(native_asset.into()),
|
||||
})),
|
||||
});
|
||||
|
||||
// Dispatched from Root to `dispatch_as` `Signed(treasury_account)`.
|
||||
assert_ok!(teleport_call.dispatch(root));
|
||||
|
||||
assert_expected_events!(
|
||||
Pezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::XcmPallet(pezpallet_xcm::Event::Sent { .. }) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
Pezkuwichain::execute_with(|| {
|
||||
type RuntimeEvent = <Pezkuwichain as Chain>::RuntimeEvent;
|
||||
type RuntimeCall = <Pezkuwichain as Chain>::RuntimeCall;
|
||||
type RuntimeOrigin = <Pezkuwichain as Chain>::RuntimeOrigin;
|
||||
type Runtime = <Pezkuwichain as Chain>::Runtime;
|
||||
type Treasury = <Pezkuwichain as PezkuwichainPallet>::Treasury;
|
||||
|
||||
// Fund Alice account from Pezkuwichain Treasury account on Asset Hub.
|
||||
|
||||
let treasury_origin: RuntimeOrigin =
|
||||
pezkuwichain_governance::pezpallet_custom_origins::Origin::Treasurer.into();
|
||||
|
||||
let alice_location: Location = [Junction::AccountId32 {
|
||||
network: None,
|
||||
id: Pezkuwichain::account_id_of(ALICE).into(),
|
||||
}]
|
||||
.into();
|
||||
let asset_hub_location: Location = [Teyrchain(1000)].into();
|
||||
let native_asset = Location::parent();
|
||||
|
||||
let treasury_spend_call = RuntimeCall::Treasury(pezpallet_treasury::Call::<Runtime>::spend {
|
||||
asset_kind: bx!(VersionedLocatableAsset::from((
|
||||
asset_hub_location.clone(),
|
||||
native_asset.into()
|
||||
))),
|
||||
amount: treasury_spend_balance,
|
||||
beneficiary: bx!(VersionedLocation::from(alice_location)),
|
||||
valid_from: None,
|
||||
});
|
||||
|
||||
assert_ok!(treasury_spend_call.dispatch(treasury_origin));
|
||||
|
||||
// Claim the spend.
|
||||
|
||||
let bob_signed = RuntimeOrigin::signed(Pezkuwichain::account_id_of(BOB));
|
||||
assert_ok!(Treasury::payout(bob_signed.clone(), 0));
|
||||
|
||||
assert_expected_events!(
|
||||
Pezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::Treasury(pezpallet_treasury::Event::AssetSpendApproved { .. }) => {},
|
||||
RuntimeEvent::Treasury(pezpallet_treasury::Event::Paid { .. }) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
type Balances = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Balances;
|
||||
|
||||
// Ensure that the funds deposited to Alice account.
|
||||
|
||||
let alice_account = AssetHubPezkuwichain::account_id_of(ALICE);
|
||||
assert_eq!(
|
||||
<Balances as Inspect<_>>::balance(&alice_account),
|
||||
treasury_spend_balance + init_alice_balance
|
||||
);
|
||||
|
||||
// Assert events triggered by xcm pay program:
|
||||
// 1. treasury asset transferred to spend beneficiary;
|
||||
// 2. response to Relay Chain Treasury pallet instance sent back;
|
||||
// 3. XCM program completed;
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::Balances(pezpallet_balances::Event::Transfer { .. }) => {},
|
||||
RuntimeEvent::TeyrchainSystem(cumulus_pallet_teyrchain_system::Event::UpwardMessageSent { .. }) => {},
|
||||
RuntimeEvent::MessageQueue(pezpallet_message_queue::Event::Processed { success: true ,.. }) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_and_claim_treasury_spend_in_usdt() {
|
||||
const SPEND_AMOUNT: u128 = 10_000_000;
|
||||
// treasury location from a sibling teyrchain.
|
||||
let treasury_location: Location = Location::new(1, PalletInstance(18));
|
||||
// treasury account on a sibling teyrchain.
|
||||
let treasury_account =
|
||||
ahr_xcm_config::LocationToAccountId::convert_location(&treasury_location).unwrap();
|
||||
let asset_hub_location = Location::new(0, Teyrchain(AssetHubPezkuwichain::para_id().into()));
|
||||
let root = <Pezkuwichain as Chain>::RuntimeOrigin::root();
|
||||
// asset kind to be spent from the treasury.
|
||||
let asset_kind: VersionedLocatableAsset =
|
||||
(asset_hub_location, AssetId((PalletInstance(50), GeneralIndex(USDT_ID.into())).into()))
|
||||
.into();
|
||||
// treasury spend beneficiary.
|
||||
let alice: AccountId = Pezkuwichain::account_id_of(ALICE);
|
||||
let bob: AccountId = Pezkuwichain::account_id_of(BOB);
|
||||
let bob_signed = <Pezkuwichain as Chain>::RuntimeOrigin::signed(bob.clone());
|
||||
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
type Assets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Assets;
|
||||
|
||||
// USDT created at genesis, mint some assets to the treasury account.
|
||||
assert_ok!(<Assets as Mutate<_>>::mint_into(USDT_ID, &treasury_account, SPEND_AMOUNT * 4));
|
||||
// beneficiary has zero balance.
|
||||
assert_eq!(<Assets as FungiblesInspect<_>>::balance(USDT_ID, &alice,), 0u128,);
|
||||
});
|
||||
|
||||
Pezkuwichain::execute_with(|| {
|
||||
type RuntimeEvent = <Pezkuwichain as Chain>::RuntimeEvent;
|
||||
type Treasury = <Pezkuwichain as PezkuwichainPallet>::Treasury;
|
||||
type AssetRate = <Pezkuwichain as PezkuwichainPallet>::AssetRate;
|
||||
|
||||
// create a conversion rate from `asset_kind` to the native currency.
|
||||
assert_ok!(AssetRate::create(root.clone(), Box::new(asset_kind.clone()), 2.into()));
|
||||
|
||||
Dmp::make_teyrchain_reachable(1000);
|
||||
|
||||
// create and approve a treasury spend.
|
||||
assert_ok!(Treasury::spend(
|
||||
root,
|
||||
Box::new(asset_kind),
|
||||
SPEND_AMOUNT,
|
||||
Box::new(Location::new(0, Into::<[u8; 32]>::into(alice.clone())).into()),
|
||||
None,
|
||||
));
|
||||
// claim the spend.
|
||||
assert_ok!(Treasury::payout(bob_signed.clone(), 0));
|
||||
|
||||
assert_expected_events!(
|
||||
Pezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::Treasury(pezpallet_treasury::Event::Paid { .. }) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
AssetHubPezkuwichain::execute_with(|| {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
type Assets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::Assets;
|
||||
|
||||
// assert events triggered by xcm pay program
|
||||
// 1. treasury asset transferred to spend beneficiary
|
||||
// 2. response to Relay Chain treasury pallet instance sent back
|
||||
// 3. XCM program completed
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::Assets(pezpallet_assets::Event::Transferred { asset_id: id, from, to, amount }) => {
|
||||
id: id == &USDT_ID,
|
||||
from: from == &treasury_account,
|
||||
to: to == &alice,
|
||||
amount: amount == &SPEND_AMOUNT,
|
||||
},
|
||||
RuntimeEvent::TeyrchainSystem(cumulus_pallet_teyrchain_system::Event::UpwardMessageSent { .. }) => {},
|
||||
RuntimeEvent::MessageQueue(pezpallet_message_queue::Event::Processed { success: true ,.. }) => {},
|
||||
]
|
||||
);
|
||||
// beneficiary received the assets from the treasury.
|
||||
assert_eq!(<Assets as FungiblesInspect<_>>::balance(USDT_ID, &alice,), SPEND_AMOUNT,);
|
||||
});
|
||||
|
||||
Pezkuwichain::execute_with(|| {
|
||||
type RuntimeEvent = <Pezkuwichain as Chain>::RuntimeEvent;
|
||||
type Treasury = <Pezkuwichain as PezkuwichainPallet>::Treasury;
|
||||
|
||||
// check the payment status to ensure the response from the AssetHub was received.
|
||||
assert_ok!(Treasury::check_status(bob_signed, 0));
|
||||
assert_expected_events!(
|
||||
Pezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::Treasury(pezpallet_treasury::Event::SpendProcessed { .. }) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
}
|
||||
+298
@@ -0,0 +1,298 @@
|
||||
// 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.
|
||||
|
||||
//! Tests for XCM fee estimation in the runtime.
|
||||
|
||||
use crate::imports::*;
|
||||
use emulated_integration_tests_common::test_can_estimate_and_pay_exact_fees;
|
||||
use pezframe_support::dispatch::RawOrigin;
|
||||
use xcm_runtime_apis::{
|
||||
dry_run::runtime_decl_for_dry_run_api::DryRunApiV2,
|
||||
fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV2,
|
||||
};
|
||||
|
||||
fn sender_assertions(test: ParaToParaThroughAHTest) {
|
||||
type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
|
||||
PenpalA::assert_xcm_pallet_attempted_complete(None);
|
||||
|
||||
assert_expected_events!(
|
||||
PenpalA,
|
||||
vec![
|
||||
RuntimeEvent::ForeignAssets(
|
||||
pezpallet_assets::Event::Burned { asset_id, owner, balance }
|
||||
) => {
|
||||
asset_id: *asset_id == Location::new(1, []),
|
||||
owner: *owner == test.sender.account_id,
|
||||
balance: *balance == test.args.amount,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
fn hop_assertions(test: ParaToParaThroughAHTest) {
|
||||
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
|
||||
AssetHubPezkuwichain::assert_xcmp_queue_success(None);
|
||||
|
||||
assert_expected_events!(
|
||||
AssetHubPezkuwichain,
|
||||
vec![
|
||||
RuntimeEvent::Balances(
|
||||
pezpallet_balances::Event::Burned { amount, .. }
|
||||
) => {
|
||||
amount: *amount > test.args.amount * 90/100,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
fn receiver_assertions(test: ParaToParaThroughAHTest) {
|
||||
type RuntimeEvent = <PenpalB as Chain>::RuntimeEvent;
|
||||
PenpalB::assert_xcmp_queue_success(None);
|
||||
|
||||
assert_expected_events!(
|
||||
PenpalB,
|
||||
vec![
|
||||
RuntimeEvent::ForeignAssets(
|
||||
pezpallet_assets::Event::Issued { asset_id, owner, .. }
|
||||
) => {
|
||||
asset_id: *asset_id == Location::new(1, []),
|
||||
owner: *owner == test.receiver.account_id,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
fn transfer_assets_para_to_para_through_ah_call(
|
||||
test: ParaToParaThroughAHTest,
|
||||
) -> <PenpalA as Chain>::RuntimeCall {
|
||||
type RuntimeCall = <PenpalA as Chain>::RuntimeCall;
|
||||
|
||||
let asset_hub_location: Location =
|
||||
PenpalB::sibling_location_of(AssetHubPezkuwichain::para_id());
|
||||
let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset {
|
||||
assets: Wild(AllCounted(test.args.assets.len() as u32)),
|
||||
beneficiary: test.args.beneficiary,
|
||||
}]);
|
||||
RuntimeCall::PezkuwiXcm(pezpallet_xcm::Call::transfer_assets_using_type_and_then {
|
||||
dest: bx!(test.args.dest.into()),
|
||||
assets: bx!(test.args.assets.clone().into()),
|
||||
assets_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())),
|
||||
remote_fees_id: bx!(VersionedAssetId::from(AssetId(Location::new(1, [])))),
|
||||
fees_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.into())),
|
||||
custom_xcm_on_dest: bx!(VersionedXcm::from(custom_xcm_on_dest)),
|
||||
weight_limit: test.args.weight_limit,
|
||||
})
|
||||
}
|
||||
|
||||
/// We are able to dry-run and estimate the fees for a multi-hop XCM journey.
|
||||
/// Scenario: Alice on PenpalA has some DOTs and wants to send them to PenpalB.
|
||||
/// We want to know the fees using the `DryRunApi` and `XcmPaymentApi`.
|
||||
#[test]
|
||||
fn multi_hop_works() {
|
||||
let destination = PenpalA::sibling_location_of(PenpalB::para_id());
|
||||
let sender = PenpalASender::get();
|
||||
let amount_to_send = 1_000_000_000_000;
|
||||
let asset_owner = PenpalAssetOwner::get();
|
||||
let assets: Assets = (Parent, amount_to_send).into();
|
||||
let fee_asset_id: AssetId = Parent.into();
|
||||
let relay_native_asset_location = Location::parent();
|
||||
let sender_as_seen_by_ah = AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id());
|
||||
let sov_of_sender_on_ah =
|
||||
AssetHubPezkuwichain::sovereign_account_id_of(sender_as_seen_by_ah.clone());
|
||||
|
||||
// fund Teyrchain's sender account
|
||||
PenpalA::mint_foreign_asset(
|
||||
<PenpalA as Chain>::RuntimeOrigin::signed(asset_owner.clone()),
|
||||
relay_native_asset_location.clone(),
|
||||
sender.clone(),
|
||||
amount_to_send * 2,
|
||||
);
|
||||
|
||||
// fund the Teyrchain Origin's SA on AssetHub with the native tokens held in reserve.
|
||||
AssetHubPezkuwichain::fund_accounts(vec![(sov_of_sender_on_ah.clone(), amount_to_send * 2)]);
|
||||
|
||||
// Init values for Teyrchain Destination
|
||||
let beneficiary_id = PenpalBReceiver::get();
|
||||
|
||||
let test_args = TestContext {
|
||||
sender: PenpalASender::get(), // Bob in PenpalB.
|
||||
receiver: PenpalBReceiver::get(), // Alice.
|
||||
args: TestArgs::new_para(
|
||||
destination,
|
||||
beneficiary_id.clone(),
|
||||
amount_to_send,
|
||||
assets,
|
||||
None,
|
||||
fee_asset_id,
|
||||
),
|
||||
};
|
||||
let mut test = ParaToParaThroughAHTest::new(test_args);
|
||||
|
||||
// We get them from the PenpalA closure.
|
||||
let mut delivery_fees_amount = 0;
|
||||
let mut remote_message = VersionedXcm::from(Xcm(Vec::new()));
|
||||
<PenpalA as TestExt>::execute_with(|| {
|
||||
type Runtime = <PenpalA as Chain>::Runtime;
|
||||
type OriginCaller = <PenpalA as Chain>::OriginCaller;
|
||||
|
||||
let call = transfer_assets_para_to_para_through_ah_call(test.clone());
|
||||
let origin = OriginCaller::system(RawOrigin::Signed(sender.clone()));
|
||||
let result = Runtime::dry_run_call(origin, call, xcm::prelude::XCM_VERSION).unwrap();
|
||||
// We filter the result to get only the messages we are interested in.
|
||||
let (destination_to_query, messages_to_query) = &result
|
||||
.forwarded_xcms
|
||||
.iter()
|
||||
.find(|(destination, _)| {
|
||||
*destination == VersionedLocation::from(Location::new(1, [Teyrchain(1000)]))
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(messages_to_query.len(), 1);
|
||||
remote_message = messages_to_query[0].clone();
|
||||
let asset_id_for_delivery_fees = VersionedAssetId::from(Location::parent());
|
||||
let delivery_fees = Runtime::query_delivery_fees(
|
||||
destination_to_query.clone(),
|
||||
remote_message.clone(),
|
||||
asset_id_for_delivery_fees,
|
||||
)
|
||||
.unwrap();
|
||||
delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees);
|
||||
});
|
||||
|
||||
// These are set in the AssetHub closure.
|
||||
let mut intermediate_execution_fees = 0;
|
||||
let mut intermediate_delivery_fees_amount = 0;
|
||||
let mut intermediate_remote_message = VersionedXcm::from(Xcm::<()>(Vec::new()));
|
||||
<AssetHubPezkuwichain as TestExt>::execute_with(|| {
|
||||
type Runtime = <AssetHubPezkuwichain as Chain>::Runtime;
|
||||
type RuntimeCall = <AssetHubPezkuwichain as Chain>::RuntimeCall;
|
||||
|
||||
// First we get the execution fees.
|
||||
let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap();
|
||||
intermediate_execution_fees = Runtime::query_weight_to_asset_fee(
|
||||
weight,
|
||||
VersionedAssetId::from(AssetId(Location::new(1, []))),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// We have to do this to turn `VersionedXcm<()>` into `VersionedXcm<RuntimeCall>`.
|
||||
let xcm_program = VersionedXcm::from(Xcm::<RuntimeCall>::from(
|
||||
remote_message.clone().try_into().unwrap(),
|
||||
));
|
||||
|
||||
// Now we get the delivery fees to the final destination.
|
||||
let result =
|
||||
Runtime::dry_run_xcm(sender_as_seen_by_ah.clone().into(), xcm_program).unwrap();
|
||||
let (destination_to_query, messages_to_query) = &result
|
||||
.forwarded_xcms
|
||||
.iter()
|
||||
.find(|(destination, _)| {
|
||||
*destination == VersionedLocation::from(Location::new(1, [Teyrchain(2001)]))
|
||||
})
|
||||
.unwrap();
|
||||
// There's actually two messages here.
|
||||
// One created when the message we sent from PenpalA arrived and was executed.
|
||||
// The second one when we dry-run the xcm.
|
||||
// We could've gotten the message from the queue without having to dry-run, but
|
||||
// offchain applications would have to dry-run, so we do it here as well.
|
||||
intermediate_remote_message = messages_to_query[0].clone();
|
||||
let asset_id_for_delivery_fees = VersionedAssetId::from(Location::parent());
|
||||
let delivery_fees = Runtime::query_delivery_fees(
|
||||
destination_to_query.clone(),
|
||||
intermediate_remote_message.clone(),
|
||||
asset_id_for_delivery_fees,
|
||||
)
|
||||
.unwrap();
|
||||
intermediate_delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees);
|
||||
});
|
||||
|
||||
// Get the final execution fees in the destination.
|
||||
let mut final_execution_fees = 0;
|
||||
<PenpalB as TestExt>::execute_with(|| {
|
||||
type Runtime = <PenpalA as Chain>::Runtime;
|
||||
|
||||
let weight = Runtime::query_xcm_weight(intermediate_remote_message.clone()).unwrap();
|
||||
final_execution_fees = Runtime::query_weight_to_asset_fee(
|
||||
weight,
|
||||
VersionedAssetId::from(AssetId(Location::parent())),
|
||||
)
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
// Dry-running is done.
|
||||
PenpalA::reset_ext();
|
||||
AssetHubPezkuwichain::reset_ext();
|
||||
PenpalB::reset_ext();
|
||||
|
||||
// Fund accounts again.
|
||||
PenpalA::mint_foreign_asset(
|
||||
<PenpalA as Chain>::RuntimeOrigin::signed(asset_owner),
|
||||
relay_native_asset_location.clone(),
|
||||
sender.clone(),
|
||||
amount_to_send * 2,
|
||||
);
|
||||
AssetHubPezkuwichain::fund_accounts(vec![(sov_of_sender_on_ah, amount_to_send * 2)]);
|
||||
|
||||
// Actually run the extrinsic.
|
||||
let sender_assets_before = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(relay_native_asset_location.clone(), &sender)
|
||||
});
|
||||
let receiver_assets_before = PenpalB::execute_with(|| {
|
||||
type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(relay_native_asset_location.clone(), &beneficiary_id)
|
||||
});
|
||||
|
||||
test.set_assertion::<PenpalA>(sender_assertions);
|
||||
test.set_assertion::<AssetHubPezkuwichain>(hop_assertions);
|
||||
test.set_assertion::<PenpalB>(receiver_assertions);
|
||||
let call = transfer_assets_para_to_para_through_ah_call(test.clone());
|
||||
test.set_call(call);
|
||||
test.assert();
|
||||
|
||||
let sender_assets_after = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(relay_native_asset_location.clone(), &sender)
|
||||
});
|
||||
let receiver_assets_after = PenpalB::execute_with(|| {
|
||||
type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(relay_native_asset_location, &beneficiary_id)
|
||||
});
|
||||
|
||||
// We know the exact fees on every hop.
|
||||
assert_eq!(
|
||||
sender_assets_after,
|
||||
sender_assets_before - amount_to_send - delivery_fees_amount /* This is charged directly
|
||||
* from the sender's
|
||||
* account. */
|
||||
);
|
||||
assert_eq!(
|
||||
receiver_assets_after,
|
||||
receiver_assets_before + amount_to_send -
|
||||
intermediate_execution_fees -
|
||||
intermediate_delivery_fees_amount -
|
||||
final_execution_fees
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_hop_pay_fees_works() {
|
||||
test_can_estimate_and_pay_exact_fees!(
|
||||
PenpalA,
|
||||
AssetHubPezkuwichain,
|
||||
PenpalB,
|
||||
(Parent, 1_000_000_000_000u128),
|
||||
Penpal
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user