Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Treasury Spend Detects Relative Locations of Native Asset #233

Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/integration-tests-matrix.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,9 @@
{
"name": "people-kusama",
"package": "people-kusama-integration-tests"
},
{
"name": "collectives-polkadot",
"package": "collectives-polkadot-integration-tests"
}
]
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Use Relay Chain's Treasury Pallet account as a destination for XCM fees on System Parachain ([polkadot-fellows/runtimes#191](https://github.com/polkadot-fellows/runtimes/pull/191))
- Bump parachains runtime API to v10 in Polkadot to enable async-backing subsystems(still in backwards compatible mode) [polkadot-fellows/runtimes#222](https://github.com/polkadot-fellows/runtimes/pull/222)
- Prepared system parachain runtimes for async backing enabling ([polkadot-fellows/runtimes#228](https://github.com/polkadot-fellows/runtimes/pull/228))
- Treasury Spend detects relative locations of the native asset ([polkadot-fellows/runtimes#233](https://github.com/polkadot-fellows/runtimes/pull/233))

### Removed

Expand Down
36 changes: 36 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ members = [
"integration-tests/emulated/tests/assets/asset-hub-polkadot",
"integration-tests/emulated/tests/bridges/bridge-hub-kusama",
"integration-tests/emulated/tests/bridges/bridge-hub-polkadot",
"integration-tests/emulated/tests/collectives/collectives-polkadot",
"integration-tests/emulated/tests/people/people-kusama",
]

Expand Down
2 changes: 2 additions & 0 deletions integration-tests/emulated/chains/relays/kusama/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ decl_test_relay_chains! {
Hrmp: kusama_runtime::Hrmp,
Identity: kusama_runtime::Identity,
IdentityMigrator: kusama_runtime::IdentityMigrator,
Treasury: kusama_runtime::Treasury,
AssetRate: kusama_runtime::AssetRate,
}
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@ frame-support = { version = "29.0.0" }
pallet-assets = { version = "30.0.0" }
pallet-balances = { version = "29.0.0" }
pallet-asset-conversion = { version = "11.0.0" }
pallet-treasury = { version = "28.0.0" }
pallet-message-queue = { version = "32.0.0" }
pallet-utility = { version = "29.0.0" }

# Polkadot
xcm = { package = "staging-xcm", version = "8.0.1" }
xcm-executor = { package = "staging-xcm-executor", default-features = false, version = "8.0.1" }
pallet-xcm = { version = "8.0.2" }
runtime-common = { package = "polkadot-runtime-common", default-features = false, version = "8.0.1" }

# Cumulus
parachains-common = { version = "8.0.0" }
Expand All @@ -36,3 +39,4 @@ integration-tests-helpers = { path = "../../../helpers" }
kusama-runtime = { package = "staging-kusama-runtime", path = "../../../../../relay/kusama" }
kusama-system-emulated-network = { path = "../../../networks/kusama-system" }
system-parachains-constants = { path = "../../../../../system-parachains/constants" }
kusama-runtime-constants = { path = "../../../../../relay/kusama/constants" }
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod send;
mod set_xcm_versions;
mod swap;
mod teleport;
mod treasury;

use crate::*;
emulated_integration_tests_common::include_penpal_create_foreign_asset_on_asset_hub!(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
// 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.

muharem marked this conversation as resolved.
Show resolved Hide resolved
use crate::*;
use emulated_integration_tests_common::accounts::{ALICE, BOB};
use frame_support::{
dispatch::RawOrigin,
sp_runtime::traits::Dispatchable,
traits::{
fungible::Inspect,
fungibles::{Create, Inspect as FungiblesInspect, Mutate},
},
};
use kusama_runtime::OriginCaller;
use kusama_runtime_constants::currency::GRAND;
use runtime_common::impls::VersionedLocatableAsset;
use xcm_executor::traits::ConvertLocation;

// Fund Treasury account on Asset Hub from Treasury account on Relay Chain with KSMs.
#[test]
fn spend_ksm_on_asset_hub() {
// initial treasury balance on Asset Hub in KSMs.
let treasury_balance = 9_000 * GRAND;
// the balance spend on Asset Hub.
let treasury_spend_balance = 1_000 * GRAND;

let init_alice_balance = AssetHubKusama::execute_with(|| {
<<AssetHubKusama as AssetHubKusamaPallet>::Balances as Inspect<_>>::balance(
&Kusama::account_id_of(ALICE),
muharem marked this conversation as resolved.
Show resolved Hide resolved
)
});

Kusama::execute_with(|| {
type RuntimeEvent = <Kusama as Chain>::RuntimeEvent;
type RuntimeCall = <Kusama as Chain>::RuntimeCall;
type Runtime = <Kusama as Chain>::Runtime;
type Balances = <Kusama as KusamaPallet>::Balances;
type Treasury = <Kusama as KusamaPallet>::Treasury;

// Fund Treasury account on Asset Hub with KSMs.

let root = <Kusama as Chain>::RuntimeOrigin::root();
let treasury_account = Treasury::account_id();

// Mist assets to Treasury account on Relay Chain.
muharem marked this conversation as resolved.
Show resolved Hide resolved
assert_ok!(Balances::force_set_balance(
root.clone(),
treasury_account.clone().into(),
treasury_balance * 2,
));

let native_asset = Location::here();
let asset_hub_location: Location = [Parachain(1000)].into();
let treasury_location_on_asset_hub: Location = (Parent, PalletInstance(18)).into();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name is confusing. Previous variables are relative to the relay, this one starts with Parent but says on_asset_hub, leading to believe that it should be relative to the relay as well.

Looks like you want the relay's treasury sovereign account. I'd probably name it relay_treasury_location and add a comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I try to avoid a prefix relay for the treasury. We have only one the Treasury, or the Polkadot/Kusama Treasury, which eventually will move from Relay chain. I rename it to treasury_location.


let teleport_call = RuntimeCall::Utility(pallet_utility::Call::<Runtime>::dispatch_as {
as_origin: bx!(OriginCaller::system(RawOrigin::Signed(treasury_account))),
call: bx!(RuntimeCall::XcmPallet(pallet_xcm::Call::<Runtime>::teleport_assets {
dest: bx!(VersionedLocation::V4(asset_hub_location.clone())),
beneficiary: bx!(VersionedLocation::V4(treasury_location_on_asset_hub)),
assets: bx!(VersionedAssets::V4(
Asset { id: native_asset.clone().into(), fun: treasury_balance.into() }.into()
)),
fee_asset_item: 0,
})),
});

// Dispatched from Root to `despatch_as` `Signed(treasury_account)`.
muharem marked this conversation as resolved.
Show resolved Hide resolved
assert_ok!(teleport_call.dispatch(root));

assert_expected_events!(
Kusama,
vec![
RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {},
]
);
});

Kusama::execute_with(|| {
type RuntimeEvent = <Kusama as Chain>::RuntimeEvent;
type RuntimeCall = <Kusama as Chain>::RuntimeCall;
type RuntimeOrigin = <Kusama as Chain>::RuntimeOrigin;
type Runtime = <Kusama as Chain>::Runtime;
type Treasury = <Kusama as KusamaPallet>::Treasury;

// Fund Alice account from Kusama Treasury account on Asset Hub.

let treasury_origin: RuntimeOrigin =
kusama_runtime::governance::pallet_custom_origins::Origin::Treasurer.into();

let alice_location: Location =
[Junction::AccountId32 { network: None, id: Kusama::account_id_of(ALICE).into() }]
.into();
let asset_hub_location: Location = [Parachain(1000)].into();
let native_asset_on_asset_hub = Location::parent();

let treasury_spend_call = RuntimeCall::Treasury(pallet_treasury::Call::<Runtime>::spend {
asset_kind: bx!(VersionedLocatableAsset::V4 {
location: asset_hub_location.clone(),
asset_id: native_asset_on_asset_hub.into(),
}),
amount: treasury_spend_balance,
beneficiary: bx!(VersionedLocation::V4(alice_location)),
valid_from: None,
});

assert_ok!(treasury_spend_call.dispatch(treasury_origin));

// Claim the spend.

let bob_signed = RuntimeOrigin::signed(Kusama::account_id_of(BOB));
assert_ok!(Treasury::payout(bob_signed.clone(), 0));

assert_expected_events!(
Kusama,
vec![
RuntimeEvent::Treasury(pallet_treasury::Event::AssetSpendApproved { .. }) => {},
RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {},
]
);
});

AssetHubKusama::execute_with(|| {
type RuntimeEvent = <AssetHubKusama as Chain>::RuntimeEvent;
type Balances = <AssetHubKusama as AssetHubKusamaPallet>::Balances;

// Ensure that the funds deposited to Alice account.

let alice_account = Kusama::account_id_of(ALICE);
muharem marked this conversation as resolved.
Show resolved Hide resolved
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!(
AssetHubKusama,
vec![
RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => {},
RuntimeEvent::ParachainSystem(cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }) => {},
RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {},
]
);
});
}

#[test]
fn create_and_claim_treasury_spend_in_usdt() {
const ASSET_ID: u32 = 1984;
const SPEND_AMOUNT: u128 = 1_000_000;
// treasury location from a sibling parachain.
let treasury_location: Location = Location::new(1, PalletInstance(18));
// treasury account on a sibling parachain.
let treasury_account =
asset_hub_kusama_runtime::xcm_config::LocationToAccountId::convert_location(
&treasury_location,
)
.unwrap();
let asset_hub_location =
v3::Location::new(0, v3::Junction::Parachain(AssetHubKusama::para_id().into()));
let root = <Kusama as Chain>::RuntimeOrigin::root();
// asset kind to be spend from the treasury.
let asset_kind = VersionedLocatableAsset::V3 {
location: asset_hub_location,
asset_id: v3::AssetId::Concrete(
(v3::Junction::PalletInstance(50), v3::Junction::GeneralIndex(ASSET_ID.into())).into(),
),
};
// treasury spend beneficiary.
let alice: AccountId = Kusama::account_id_of(ALICE);
let bob: AccountId = Kusama::account_id_of(BOB);
let bob_signed = <Kusama as Chain>::RuntimeOrigin::signed(bob.clone());

AssetHubKusama::execute_with(|| {
type Assets = <AssetHubKusama as AssetHubKusamaPallet>::Assets;

// create an asset class and mint some assets to the treasury account.
assert_ok!(<Assets as Create<_>>::create(
ASSET_ID,
treasury_account.clone(),
true,
SPEND_AMOUNT / 2
));
assert_ok!(<Assets as Mutate<_>>::mint_into(ASSET_ID, &treasury_account, SPEND_AMOUNT * 4));
// beneficiary has zero balance.
assert_eq!(<Assets as FungiblesInspect<_>>::balance(ASSET_ID, &alice,), 0u128,);
});

Kusama::execute_with(|| {
type RuntimeEvent = <Kusama as Chain>::RuntimeEvent;
type Treasury = <Kusama as KusamaPallet>::Treasury;
type AssetRate = <Kusama as KusamaPallet>::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()));

// 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!(
Kusama,
vec![
RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {},
]
);
});

AssetHubKusama::execute_with(|| {
type RuntimeEvent = <AssetHubKusama as Chain>::RuntimeEvent;
type Assets = <AssetHubKusama as AssetHubKusamaPallet>::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!(
AssetHubKusama,
vec![
RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: id, from, to, amount }) => {
id: id == &ASSET_ID,
from: from == &treasury_account,
to: to == &alice,
amount: amount == &SPEND_AMOUNT,
},
RuntimeEvent::ParachainSystem(cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }) => {},
RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {},
]
);
// beneficiary received the assets from the treasury.
assert_eq!(<Assets as FungiblesInspect<_>>::balance(ASSET_ID, &alice,), SPEND_AMOUNT,);
});

Kusama::execute_with(|| {
type RuntimeEvent = <Kusama as Chain>::RuntimeEvent;
type Treasury = <Kusama as KusamaPallet>::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!(
Kusama,
vec![
RuntimeEvent::Treasury(pallet_treasury::Event::SpendProcessed { .. }) => {},
]
);
});
}
Loading
Loading