// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see .
use super::*;
#[test]
fn exchange_asset_should_work() {
AllowUnpaidFrom::set(vec![Parent.into()]);
add_asset(Parent, (Parent, 1000u128));
set_exchange_assets(vec![(Here, 100u128).into()]);
let message = Xcm(vec![
WithdrawAsset((Parent, 100u128).into()),
SetAppendix(
vec![DepositAsset { assets: AllCounted(2).into(), beneficiary: Parent.into() }].into(),
),
ExchangeAsset {
give: Definite((Parent, 50u128).into()),
want: (Here, 50u128).into(),
maximal: true,
},
]);
let hash = fake_message_hash(&message);
let r =
XcmExecutor::::execute_xcm(Parent, message, hash, Weight::from_parts(50, 50));
assert_eq!(r, Outcome::Complete(Weight::from_parts(40, 40)));
assert_eq!(asset_list(Parent), vec![(Here, 100u128).into(), (Parent, 950u128).into()]);
assert_eq!(exchange_assets(), vec![(Parent, 50u128).into()].into());
}
#[test]
fn exchange_asset_without_maximal_should_work() {
AllowUnpaidFrom::set(vec![Parent.into()]);
add_asset(Parent, (Parent, 1000u128));
set_exchange_assets(vec![(Here, 100u128).into()]);
let message = Xcm(vec![
WithdrawAsset((Parent, 100u128).into()),
SetAppendix(
vec![DepositAsset { assets: AllCounted(2).into(), beneficiary: Parent.into() }].into(),
),
ExchangeAsset {
give: Definite((Parent, 50).into()),
want: (Here, 50u128).into(),
maximal: false,
},
]);
let hash = fake_message_hash(&message);
let r =
XcmExecutor::::execute_xcm(Parent, message, hash, Weight::from_parts(50, 50));
assert_eq!(r, Outcome::Complete(Weight::from_parts(40, 40)));
assert_eq!(asset_list(Parent), vec![(Here, 50u128).into(), (Parent, 950u128).into()]);
assert_eq!(exchange_assets(), vec![(Here, 50u128).into(), (Parent, 50u128).into()].into());
}
#[test]
fn exchange_asset_should_fail_when_no_deal_possible() {
AllowUnpaidFrom::set(vec![Parent.into()]);
add_asset(Parent, (Parent, 1000u128));
set_exchange_assets(vec![(Here, 100u128).into()]);
let message = Xcm(vec![
WithdrawAsset((Parent, 150u128).into()),
SetAppendix(
vec![DepositAsset { assets: AllCounted(2).into(), beneficiary: Parent.into() }].into(),
),
ExchangeAsset {
give: Definite((Parent, 150u128).into()),
want: (Here, 150u128).into(),
maximal: false,
},
]);
let hash = fake_message_hash(&message);
let r =
XcmExecutor::::execute_xcm(Parent, message, hash, Weight::from_parts(50, 50));
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(40, 40), XcmError::NoDeal));
assert_eq!(asset_list(Parent), vec![(Parent, 1000u128).into()]);
assert_eq!(exchange_assets(), vec![(Here, 100u128).into()].into());
}
#[test]
fn paying_reserve_deposit_should_work() {
AllowPaidFrom::set(vec![Parent.into()]);
add_reserve(Parent.into(), (Parent, WildFungible).into());
WeightPrice::set((Parent.into(), 1_000_000_000_000, 1024 * 1024));
let fees = (Parent, 60u128).into();
let message = Xcm(vec![
ReserveAssetDeposited((Parent, 100u128).into()),
BuyExecution { fees, weight_limit: Limited(Weight::from_parts(30, 30)) },
DepositAsset { assets: AllCounted(1).into(), beneficiary: Here.into() },
]);
let hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(50, 50);
let r = XcmExecutor::::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(30, 30)));
assert_eq!(asset_list(Here), vec![(Parent, 40u128).into()]);
}
#[test]
fn transfer_should_work() {
// we'll let them have message execution for free.
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
// Child parachain #1 owns 1000 tokens held by us in reserve.
add_asset(Parachain(1), (Here, 1000));
// They want to transfer 100 of them to their sibling parachain #2
let message = Xcm(vec![TransferAsset {
assets: (Here, 100u128).into(),
beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(),
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::::execute_xcm(
Parachain(1),
message,
hash,
Weight::from_parts(50, 50),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
assert_eq!(
asset_list(AccountIndex64 { index: 3, network: None }),
vec![(Here, 100u128).into()]
);
assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]);
assert_eq!(sent_xcm(), vec![]);
}
#[test]
fn reserve_transfer_should_work() {
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
// Child parachain #1 owns 1000 tokens held by us in reserve.
add_asset(Parachain(1), (Here, 1000));
// The remote account owned by gav.
let three: MultiLocation = X1(AccountIndex64 { index: 3, network: None }).into();
// They want to transfer 100 of our native asset from sovereign account of parachain #1 into #2
// and let them know to hand it to account #3.
let message = Xcm(vec![TransferReserveAsset {
assets: (Here, 100u128).into(),
dest: Parachain(2).into(),
xcm: Xcm::<()>(vec![DepositAsset {
assets: AllCounted(1).into(),
beneficiary: three.clone(),
}]),
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::::execute_xcm(
Parachain(1),
message,
hash,
Weight::from_parts(50, 50),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
let expected_msg = Xcm::<()>(vec![
ReserveAssetDeposited((Parent, 100u128).into()),
ClearOrigin,
DepositAsset { assets: AllCounted(1).into(), beneficiary: three },
]);
let expected_hash = fake_message_hash(&expected_msg);
assert_eq!(asset_list(Parachain(2)), vec![(Here, 100).into()]);
assert_eq!(sent_xcm(), vec![(Parachain(2).into(), expected_msg, expected_hash)]);
}
#[test]
fn burn_should_work() {
// we'll let them have message execution for free.
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
// Child parachain #1 owns 1000 tokens held by us in reserve.
add_asset(Parachain(1), (Here, 1000));
// They want to burn 100 of them
let message = Xcm(vec![
WithdrawAsset((Here, 1000u128).into()),
BurnAsset((Here, 100u128).into()),
DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Parachain(1).into() },
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::::execute_xcm(
Parachain(1),
message,
hash,
Weight::from_parts(50, 50),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(30, 30)));
assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]);
assert_eq!(sent_xcm(), vec![]);
// Now they want to burn 1000 of them, which will actually only burn 900.
let message = Xcm(vec![
WithdrawAsset((Here, 900u128).into()),
BurnAsset((Here, 1000u128).into()),
DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Parachain(1).into() },
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::::execute_xcm(
Parachain(1),
message,
hash,
Weight::from_parts(50, 50),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(30, 30)));
assert_eq!(asset_list(Parachain(1)), vec![]);
assert_eq!(sent_xcm(), vec![]);
}
#[test]
fn basic_asset_trap_should_work() {
// we'll let them have message execution for free.
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into(), X1(Parachain(2)).into()]);
// Child parachain #1 owns 1000 tokens held by us in reserve.
add_asset(Parachain(1), (Here, 1000));
// They want to transfer 100 of them to their sibling parachain #2 but have a problem
let message = Xcm(vec![
WithdrawAsset((Here, 100u128).into()),
DepositAsset {
assets: Wild(AllCounted(0)), // <<< 0 is an error.
beneficiary: AccountIndex64 { index: 3, network: None }.into(),
},
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::::execute_xcm(
Parachain(1),
message,
hash,
Weight::from_parts(20, 20),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(25, 25)));
assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]);
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![]);
// Incorrect ticket doesn't work.
let message = Xcm(vec![
ClaimAsset { assets: (Here, 100u128).into(), ticket: GeneralIndex(1).into() },
DepositAsset {
assets: Wild(AllCounted(1)),
beneficiary: AccountIndex64 { index: 3, network: None }.into(),
},
]);
let hash = fake_message_hash(&message);
let old_trapped_assets = TrappedAssets::get();
let r = XcmExecutor::::execute_xcm(
Parachain(1),
message,
hash,
Weight::from_parts(20, 20),
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::UnknownClaim));
assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]);
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![]);
assert_eq!(old_trapped_assets, TrappedAssets::get());
// Incorrect origin doesn't work.
let message = Xcm(vec![
ClaimAsset { assets: (Here, 100u128).into(), ticket: GeneralIndex(0).into() },
DepositAsset {
assets: Wild(AllCounted(1)),
beneficiary: AccountIndex64 { index: 3, network: None }.into(),
},
]);
let hash = fake_message_hash(&message);
let old_trapped_assets = TrappedAssets::get();
let r = XcmExecutor::::execute_xcm(
Parachain(2),
message,
hash,
Weight::from_parts(20, 20),
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::UnknownClaim));
assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]);
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![]);
assert_eq!(old_trapped_assets, TrappedAssets::get());
// Incorrect assets doesn't work.
let message = Xcm(vec![
ClaimAsset { assets: (Here, 101u128).into(), ticket: GeneralIndex(0).into() },
DepositAsset {
assets: Wild(AllCounted(1)),
beneficiary: AccountIndex64 { index: 3, network: None }.into(),
},
]);
let hash = fake_message_hash(&message);
let old_trapped_assets = TrappedAssets::get();
let r = XcmExecutor::::execute_xcm(
Parachain(1),
message,
hash,
Weight::from_parts(20, 20),
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::UnknownClaim));
assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]);
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![]);
assert_eq!(old_trapped_assets, TrappedAssets::get());
let message = Xcm(vec![
ClaimAsset { assets: (Here, 100u128).into(), ticket: GeneralIndex(0).into() },
DepositAsset {
assets: Wild(AllCounted(1)),
beneficiary: AccountIndex64 { index: 3, network: None }.into(),
},
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::::execute_xcm(
Parachain(1),
message,
hash,
Weight::from_parts(20, 20),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(20, 20)));
assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]);
assert_eq!(
asset_list(AccountIndex64 { index: 3, network: None }),
vec![(Here, 100u128).into()]
);
// Same again doesn't work :-)
let message = Xcm(vec![
ClaimAsset { assets: (Here, 100u128).into(), ticket: GeneralIndex(0).into() },
DepositAsset {
assets: Wild(AllCounted(1)),
beneficiary: AccountIndex64 { index: 3, network: None }.into(),
},
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::::execute_xcm(
Parachain(1),
message,
hash,
Weight::from_parts(20, 20),
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::UnknownClaim));
}
#[test]
fn max_assets_limit_should_work() {
// we'll let them have message execution for free.
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
// Child parachain #1 owns 1000 tokens held by us in reserve.
add_asset(Parachain(1), ([1u8; 32], 1000u128));
add_asset(Parachain(1), ([2u8; 32], 1000u128));
add_asset(Parachain(1), ([3u8; 32], 1000u128));
add_asset(Parachain(1), ([4u8; 32], 1000u128));
add_asset(Parachain(1), ([5u8; 32], 1000u128));
add_asset(Parachain(1), ([6u8; 32], 1000u128));
add_asset(Parachain(1), ([7u8; 32], 1000u128));
add_asset(Parachain(1), ([8u8; 32], 1000u128));
add_asset(Parachain(1), ([9u8; 32], 1000u128));
// Attempt to withdraw 8 (=2x4)different assets. This will succeed.
let message = Xcm(vec![
WithdrawAsset(([1u8; 32], 100u128).into()),
WithdrawAsset(([2u8; 32], 100u128).into()),
WithdrawAsset(([3u8; 32], 100u128).into()),
WithdrawAsset(([4u8; 32], 100u128).into()),
WithdrawAsset(([5u8; 32], 100u128).into()),
WithdrawAsset(([6u8; 32], 100u128).into()),
WithdrawAsset(([7u8; 32], 100u128).into()),
WithdrawAsset(([8u8; 32], 100u128).into()),
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::::execute_xcm(
Parachain(1),
message,
hash,
Weight::from_parts(100, 100),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(85, 85)));
// Attempt to withdraw 9 different assets will fail.
let message = Xcm(vec![
WithdrawAsset(([1u8; 32], 100u128).into()),
WithdrawAsset(([2u8; 32], 100u128).into()),
WithdrawAsset(([3u8; 32], 100u128).into()),
WithdrawAsset(([4u8; 32], 100u128).into()),
WithdrawAsset(([5u8; 32], 100u128).into()),
WithdrawAsset(([6u8; 32], 100u128).into()),
WithdrawAsset(([7u8; 32], 100u128).into()),
WithdrawAsset(([8u8; 32], 100u128).into()),
WithdrawAsset(([9u8; 32], 100u128).into()),
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::::execute_xcm(
Parachain(1),
message,
hash,
Weight::from_parts(100, 100),
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(95, 95), XcmError::HoldingWouldOverflow));
// Attempt to withdraw 4 different assets and then the same 4 and then a different 4 will
// succeed.
let message = Xcm(vec![
WithdrawAsset(([1u8; 32], 100u128).into()),
WithdrawAsset(([2u8; 32], 100u128).into()),
WithdrawAsset(([3u8; 32], 100u128).into()),
WithdrawAsset(([4u8; 32], 100u128).into()),
WithdrawAsset(([1u8; 32], 100u128).into()),
WithdrawAsset(([2u8; 32], 100u128).into()),
WithdrawAsset(([3u8; 32], 100u128).into()),
WithdrawAsset(([4u8; 32], 100u128).into()),
WithdrawAsset(([5u8; 32], 100u128).into()),
WithdrawAsset(([6u8; 32], 100u128).into()),
WithdrawAsset(([7u8; 32], 100u128).into()),
WithdrawAsset(([8u8; 32], 100u128).into()),
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::::execute_xcm(
Parachain(1),
message,
hash,
Weight::from_parts(200, 200),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(125, 125)));
// Attempt to withdraw 4 different assets and then a different 4 and then the same 4 will fail.
let message = Xcm(vec![
WithdrawAsset(([1u8; 32], 100u128).into()),
WithdrawAsset(([2u8; 32], 100u128).into()),
WithdrawAsset(([3u8; 32], 100u128).into()),
WithdrawAsset(([4u8; 32], 100u128).into()),
WithdrawAsset(([5u8; 32], 100u128).into()),
WithdrawAsset(([6u8; 32], 100u128).into()),
WithdrawAsset(([7u8; 32], 100u128).into()),
WithdrawAsset(([8u8; 32], 100u128).into()),
WithdrawAsset(([1u8; 32], 100u128).into()),
WithdrawAsset(([2u8; 32], 100u128).into()),
WithdrawAsset(([3u8; 32], 100u128).into()),
WithdrawAsset(([4u8; 32], 100u128).into()),
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::::execute_xcm(
Parachain(1),
message,
hash,
Weight::from_parts(200, 200),
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(95, 95), XcmError::HoldingWouldOverflow));
// Attempt to withdraw 4 different assets and then a different 4 and then the same 4 will fail.
let message = Xcm(vec![
WithdrawAsset(MultiAssets::from(vec![
([1u8; 32], 100u128).into(),
([2u8; 32], 100u128).into(),
([3u8; 32], 100u128).into(),
([4u8; 32], 100u128).into(),
([5u8; 32], 100u128).into(),
([6u8; 32], 100u128).into(),
([7u8; 32], 100u128).into(),
([8u8; 32], 100u128).into(),
])),
WithdrawAsset(([1u8; 32], 100u128).into()),
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::::execute_xcm(
Parachain(1),
message,
hash,
Weight::from_parts(200, 200),
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(25, 25), XcmError::HoldingWouldOverflow));
}