Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

XCM: Fix issue with RequestUnlock #7278

Merged
merged 5 commits into from
May 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions xcm/xcm-builder/src/tests/locking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ fn remote_unlock_roundtrip_should_work() {
set_send_price((Parent, 10u128));

// We have been told by Parachain #1 that Account #3 has locked funds which we can unlock.
// Previously, we must have sent a LockAsset instruction to Parachain #1.
// This caused Parachain #1 to send us the NoteUnlockable instruction.
let message =
Xcm(vec![NoteUnlockable { asset: (Parent, 100u128).into(), owner: (3u64,).into() }]);
let hash = fake_message_hash(&message);
Expand Down Expand Up @@ -169,8 +171,10 @@ fn remote_unlock_roundtrip_should_work() {
assert_eq!(r, Outcome::Complete(Weight::from_parts(40, 40)));
assert_eq!(asset_list((3u64,)), vec![(Parent, 990u128).into()]);

let expected_msg =
Xcm::<()>(vec![UnlockAsset { target: (3u64,).into(), asset: (Parent, 100u128).into() }]);
let expected_msg = Xcm::<()>(vec![UnlockAsset {
target: (Parent, Parachain(42), 3u64).into(),
asset: (Parent, 100u128).into(),
}]);
let expected_hash = fake_message_hash(&expected_msg);
assert_eq!(sent_xcm(), vec![((Parent, Parachain(1)).into(), expected_msg, expected_hash)]);
assert_eq!(
Expand Down
15 changes: 14 additions & 1 deletion xcm/xcm-executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -876,9 +876,11 @@ impl<Config: config::Config> XcmExecutor<Config> {
RequestUnlock { asset, locker } => {
let origin = *self.origin_ref().ok_or(XcmError::BadOrigin)?;
let remote_asset = Self::try_reanchor(asset.clone(), &locker)?.0;
let remote_target = Self::try_reanchor_multilocation(origin, &locker)?.0;
let reduce_ticket =
Config::AssetLocker::prepare_reduce_unlockable(locker, asset, origin)?;
let msg = Xcm::<()>(vec![UnlockAsset { asset: remote_asset, target: origin }]);
let msg =
Xcm::<()>(vec![UnlockAsset { asset: remote_asset, target: remote_target }]);
let (ticket, price) = validate_send::<Config::XcmSender>(locker, msg)?;
self.take_fee(price, FeeReason::RequestUnlock)?;
reduce_ticket.enact()?;
Expand Down Expand Up @@ -990,6 +992,17 @@ impl<Config: config::Config> XcmExecutor<Config> {
Ok((asset, reanchor_context))
}

fn try_reanchor_multilocation(
location: MultiLocation,
destination: &MultiLocation,
) -> Result<(MultiLocation, InteriorMultiLocation), XcmError> {
franciscoaguirre marked this conversation as resolved.
Show resolved Hide resolved
let reanchor_context = Config::UniversalLocation::get();
let location = location
.reanchored(&destination, reanchor_context)
.map_err(|_| XcmError::ReanchorFailed)?;
Ok((location, reanchor_context))
}

/// NOTE: Any assets which were unable to be reanchored are introduced into `failed_bin`.
fn reanchored(
mut assets: Assets,
Expand Down
26 changes: 24 additions & 2 deletions xcm/xcm-simulator/example/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,15 +272,15 @@ mod tests {
}

#[test]
fn remote_locking() {
fn remote_locking_and_unlocking() {
MockNet::reset();

let locked_amount = 100;

ParaB::execute_with(|| {
let message = Xcm(vec![LockAsset {
asset: (Here, locked_amount).into(),
unlocker: (Parachain(1),).into(),
unlocker: Parachain(1).into(),
}]);
assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone()));
});
Expand All @@ -306,6 +306,28 @@ mod tests {
}])]
);
});

ParaB::execute_with(|| {
// Request unlocking part of the funds on the relay chain
let message = Xcm(vec![RequestUnlock {
asset: (Parent, locked_amount - 50).into(),
locker: Parent.into(),
}]);
assert_ok!(ParachainPalletXcm::send_xcm(Here, (Parent, Parachain(1)), message));
});

Relay::execute_with(|| {
use pallet_balances::{BalanceLock, Reasons};
// Lock is reduced
assert_eq!(
relay_chain::Balances::locks(&child_account_id(2)),
vec![BalanceLock {
id: *b"py/xcmlk",
amount: locked_amount - 50,
reasons: Reasons::All
}]
);
});
}

/// Scenario:
Expand Down
29 changes: 23 additions & 6 deletions xcm/xcm-simulator/example/src/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@
//! Parachain runtime mock.

use codec::{Decode, Encode};
use core::marker::PhantomData;
use frame_support::{
construct_runtime, parameter_types,
traits::{EnsureOrigin, EnsureOriginWithArg, Everything, EverythingBut, Nothing},
traits::{ContainsPair, EnsureOrigin, EnsureOriginWithArg, Everything, EverythingBut, Nothing},
weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight},
};

use frame_system::EnsureRoot;
use sp_core::{ConstU32, H256};
use sp_runtime::{
testing::Header,
traits::{Hash, IdentityLookup},
traits::{Get, Hash, IdentityLookup},
AccountId32,
};
use sp_std::prelude::*;
Expand Down Expand Up @@ -238,7 +239,7 @@ impl Config for XcmConfig {
type Trader = FixedRateOfFungible<KsmPerSecondPerByte, ()>;
type ResponseHandler = ();
type AssetTrap = ();
type AssetLocker = ();
type AssetLocker = PolkadotXcm;
type AssetExchanger = ();
type AssetClaims = ();
type SubscriptionService = ();
Expand Down Expand Up @@ -325,7 +326,7 @@ pub mod mock_msg_queue {
Ok(xcm) => {
let location = (Parent, Parachain(sender.into()));
match T::XcmExecutor::execute_xcm(location, xcm, message_hash, max_weight) {
Outcome::Error(e) => (Err(e.clone()), Event::Fail(Some(hash), e)),
Outcome::Error(e) => (Err(e), Event::Fail(Some(hash), e)),
Outcome::Complete(w) => (Ok(w), Event::Success(Some(hash))),
// As far as the caller is concerned, this was dispatched without error, so
// we just report the weight used.
Expand All @@ -349,7 +350,7 @@ pub mod mock_msg_queue {
let _ = XcmpMessageFormat::decode(&mut data_ref)
.expect("Simulator encodes with versioned xcm format; qed");

let mut remaining_fragments = &data_ref[..];
let mut remaining_fragments = data_ref;
while !remaining_fragments.is_empty() {
if let Ok(xcm) =
VersionedXcm::<T::RuntimeCall>::decode(&mut remaining_fragments)
Expand Down Expand Up @@ -403,6 +404,22 @@ parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}

pub struct TrustedLockerCase<T>(PhantomData<T>);
impl<T: Get<(MultiLocation, MultiAssetFilter)>> ContainsPair<MultiLocation, MultiAsset>
for TrustedLockerCase<T>
{
fn contains(origin: &MultiLocation, asset: &MultiAsset) -> bool {
let (o, a) = T::get();
a.matches(asset) && &o == origin
}
}

parameter_types! {
pub RelayTokenForRelay: (MultiLocation, MultiAssetFilter) = (Parent.into(), Wild(AllOf { id: Concrete(Parent.into()), fun: WildFungible }));
}

pub type TrustedLockers = TrustedLockerCase<RelayTokenForRelay>;

impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
Expand All @@ -420,7 +437,7 @@ impl pallet_xcm::Config for Runtime {
type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
type Currency = Balances;
type CurrencyMatcher = ();
type TrustedLockers = ();
type TrustedLockers = TrustedLockers;
type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>;
type MaxRemoteLockConsumers = ConstU32<0>;
Expand Down