-
Notifications
You must be signed in to change notification settings - Fork 771
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
FRAME: Unity Balance Conversion for Different IDs of Native Asset #3659
Changes from all commits
8acac24
f7217a5
870c2ec
5d4bdb2
023d778
e311e50
9d59fa3
67ce378
6569e30
190e224
d3fcd1c
d294d38
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,3 +19,4 @@ mod send; | |
mod set_xcm_versions; | ||
mod swap; | ||
mod teleport; | ||
mod treasury; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
// 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}; | ||
use frame_support::{ | ||
dispatch::RawOrigin, | ||
sp_runtime::traits::Dispatchable, | ||
traits::{ | ||
fungible::Inspect, | ||
fungibles::{Create, Inspect as FungiblesInspect, Mutate}, | ||
}, | ||
}; | ||
use parachains_common::AccountId; | ||
use polkadot_runtime_common::impls::VersionedLocatableAsset; | ||
use rococo_runtime::OriginCaller; | ||
use rococo_runtime_constants::currency::GRAND; | ||
use xcm_executor::traits::ConvertLocation; | ||
|
||
// Fund Treasury account on Asset Hub from Treasury account on Relay Chain with ROCs. | ||
#[test] | ||
fn spend_roc_on_asset_hub() { | ||
// initial treasury balance on Asset Hub in ROCs. | ||
let treasury_balance = 9_000 * GRAND; | ||
// the balance spend on Asset Hub. | ||
let treasury_spend_balance = 1_000 * GRAND; | ||
|
||
let init_alice_balance = AssetHubRococo::execute_with(|| { | ||
<<AssetHubRococo as AssetHubRococoPallet>::Balances as Inspect<_>>::balance( | ||
&AssetHubRococo::account_id_of(ALICE), | ||
) | ||
}); | ||
|
||
Rococo::execute_with(|| { | ||
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent; | ||
type RuntimeCall = <Rococo as Chain>::RuntimeCall; | ||
type Runtime = <Rococo as Chain>::Runtime; | ||
type Balances = <Rococo as RococoPallet>::Balances; | ||
type Treasury = <Rococo as RococoPallet>::Treasury; | ||
|
||
// Fund Treasury account on Asset Hub with ROCs. | ||
|
||
let root = <Rococo 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, | ||
)); | ||
|
||
let native_asset = Location::here(); | ||
let asset_hub_location: Location = [Parachain(1000)].into(); | ||
let treasury_location: Location = (Parent, PalletInstance(18)).into(); | ||
|
||
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)), | ||
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)`. | ||
assert_ok!(teleport_call.dispatch(root)); | ||
|
||
assert_expected_events!( | ||
Rococo, | ||
vec![ | ||
RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, | ||
] | ||
); | ||
}); | ||
|
||
Rococo::execute_with(|| { | ||
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent; | ||
type RuntimeCall = <Rococo as Chain>::RuntimeCall; | ||
type RuntimeOrigin = <Rococo as Chain>::RuntimeOrigin; | ||
type Runtime = <Rococo as Chain>::Runtime; | ||
type Treasury = <Rococo as RococoPallet>::Treasury; | ||
|
||
// Fund Alice account from Rococo Treasury account on Asset Hub. | ||
|
||
let treasury_origin: RuntimeOrigin = | ||
rococo_runtime::governance::pallet_custom_origins::Origin::Treasurer.into(); | ||
|
||
let alice_location: Location = | ||
[Junction::AccountId32 { network: None, id: Rococo::account_id_of(ALICE).into() }] | ||
.into(); | ||
let asset_hub_location: Location = [Parachain(1000)].into(); | ||
let native_asset = 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.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(Rococo::account_id_of(BOB)); | ||
assert_ok!(Treasury::payout(bob_signed.clone(), 0)); | ||
|
||
assert_expected_events!( | ||
Rococo, | ||
vec![ | ||
RuntimeEvent::Treasury(pallet_treasury::Event::AssetSpendApproved { .. }) => {}, | ||
RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {}, | ||
] | ||
); | ||
}); | ||
|
||
AssetHubRococo::execute_with(|| { | ||
type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent; | ||
type Balances = <AssetHubRococo as AssetHubRococoPallet>::Balances; | ||
|
||
// Ensure that the funds deposited to Alice account. | ||
|
||
let alice_account = AssetHubRococo::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!( | ||
AssetHubRococo, | ||
vec![ | ||
RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => {}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could specify the beneficiary here, so we know the transfer is working There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this assert is broken, I cannot really match beneficiary here. but we are fine here, I check the balance above |
||
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_rococo_runtime::xcm_config::LocationToAccountId::convert_location( | ||
&treasury_location, | ||
) | ||
.unwrap(); | ||
let asset_hub_location = | ||
v3::Location::new(0, v3::Junction::Parachain(AssetHubRococo::para_id().into())); | ||
let root = <Rococo 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 = Rococo::account_id_of(ALICE); | ||
let bob: AccountId = Rococo::account_id_of(BOB); | ||
let bob_signed = <Rococo as Chain>::RuntimeOrigin::signed(bob.clone()); | ||
|
||
AssetHubRococo::execute_with(|| { | ||
type Assets = <AssetHubRococo as AssetHubRococoPallet>::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,); | ||
}); | ||
|
||
Rococo::execute_with(|| { | ||
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent; | ||
type Treasury = <Rococo as RococoPallet>::Treasury; | ||
type AssetRate = <Rococo as RococoPallet>::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!( | ||
Rococo, | ||
vec![ | ||
RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably the beneficiary of this can be asserted as well There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It does not work right now with this macro |
||
] | ||
); | ||
}); | ||
|
||
AssetHubRococo::execute_with(|| { | ||
type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent; | ||
type Assets = <AssetHubRococo as AssetHubRococoPallet>::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!( | ||
AssetHubRococo, | ||
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,); | ||
}); | ||
|
||
Rococo::execute_with(|| { | ||
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent; | ||
type Treasury = <Rococo as RococoPallet>::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!( | ||
Rococo, | ||
vec![ | ||
RuntimeEvent::Treasury(pallet_treasury::Event::SpendProcessed { .. }) => {}, | ||
] | ||
); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's weird how the location is relative to the relay chain but the asset id is relative to asset hub. Is this correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, this is correct. DOT is parent on asset hub