-
Notifications
You must be signed in to change notification settings - Fork 739
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
Conversation
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.
lgmt, just two nits and I didn't check integration tests, just runtimes and xcm stuff
polkadot/runtime/common/src/impls.rs
Outdated
/// Adapter for [`Contains`] trait to match [`VersionedLocatableAsset`] type converted to the latest | ||
/// version of itself where it's location matched by `L` and it's asset id by `A` parameter types. | ||
pub struct ContainsLatest<L, A>(PhantomData<(L, A)>); | ||
impl<L, A> Contains<VersionedLocatableAsset> for ContainsLatest<L, A> |
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.
I would move it to the xcm-builder
, maybe here: https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm/xcm-builder/src/matches_location.rs ?
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 implemented over VersionedLocatableAsset
type, which is part of common.
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.
I see, I thought VersionedLocatableAsset
was part of the XCM stuff, so maybe we could move everything related to VersionedLocatableAsset
and ContainsLatest
to one place in the XCM builder., e.g.:
https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm/xcm-builder/src/locatable_asset.rs.
(I think I saw some complaints about adding too much stuff to the polkadot-runtime-common
.)
As I see, we already have LocatableAssetId
in xcm-builder
here: https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm/xcm-builder/src/pay.rs#L191-L198, which could possibly also go to the locatable_asset.rs
And maybe VersionedLocatableAsset
could also wrap that LocatableAssetId
, but I think this can be just from V5, e.g.:
pub enum VersionedLocatableAsset {
...
#[codec(index = 4)]
- V4 { location: xcm::v4::Location, asset_id: xcm::v4::AssetId },
+ V4(LocatableAssetId),
}
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.
I wont wrap use LocatableAssetId
directly for the last version from VersionedLocatableAsset
. It will be confusion, different version will look different.
For now, I will keep everything as it is, specially wont change it with this PR.
Every time someone see these types, ( VersionedLocatableAsset
and LocatableAssetId
), they suggest to remove it and use only Location
, refactor it somehow, etc. Since we should be more conservative with xcm-builder, I would not move it for now.
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.
Since we should be more conservative with xcm-builder...
Where is this coming from? Can you elaborate more?
Every time someone see these types, (
VersionedLocatableAsset
andLocatableAssetId
), they suggest to remove it and use onlyLocation
, refactor it somehow, etc.
Well, perhaps it's worth considering refactoring it then.
I think keeping VersionedLocatableAsset
outside of xcm
/ xcm-builder
, where we currently have all Versioned*
stuff and also LocatableAssetId
, seems kind of strange. As far as I can see, it is used by relay runtimes and collectives runtime, so from this perspective, polkadot-runtime-common
is not the best place (xcm-builder
seems better):
[package]
name = "polkadot-runtime-common"
description = "Pallets and constants used in Relay Chain networks."
VersionedLocatableAsset
contains v3 and v4. How do you propose keeping this up-to-date? Do you expect that when we add xcm::v5
, someone will also update this? If so, there's no way to know from the xcm module's point of view (considering that one day we might move xcm out of polkadot-sdk) that some versioned stuff is used elsewhere. If not, for example, when we add xcm::v6
, we remove xcm:v3
. Is that okay? I think the check-migrations jobs should detect this and fail.
Another thing to consider, I see it is used for pallet_collective
as the key for ConversionRateToNative
or pallet_treasury
as AssetKind
. I think it's a similar situation to what's discussed here: #1130. And if I recall correctly, the last time we spoke with Joe about pallet_assets
and Location
as AssetId
, everything pointed to the solution of using xcm::latest::prelude::Location
as AssetId
(with migrations) and VersionedLocation
as AssetIdParameter
(which is used for extrinsics).
I think VersionedLocatableAsset
presents a very similar situation. Perhaps it's worth considering splitting AssetKind
into AssetKind
/ AssetKindParameter
. For example, this could help avoid using Box
for extrinsic parameters like asset_kind: Box<T::AssetKind>
, though I'm not sure if this is good or bad, it can be left for the runtime to decide. My point is that ideally, we should have one method/pattern for storing XCM-related data.
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.
I will check that draft PR, and I am also looking for a solution where that PayOverXcm can also detect that the asset is located on local chan, but beneficiary is on Asset Hub. We have this use case when treasury wants to fund it's own account on Asset Hub. I will initiate a discussion around it, and open an RFC.
@franciscoaguirre please approve this PR if you happy with it.
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.
I only want to understand the purpose of this change. Is it because DOT was being passed on to the asset rate converter? Or is it to allow things like USDT to be used 1:1 when they come from system parachains?
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.
Hmm, with sovereign accounts it definitely becomes harder. My draft PR was of the idea that we could just use the beneficiary location to know to which chain to send it to. It wouldn't work when we want to send it somewhere different than the location to fund a sovereign account.
We might need then a location for the chain and another for the beneficiary, like on the send
extrinsic in pallet-xcm. There's no need to name it locatable asset though, just a regular asset, a regular destination, and a regular beneficiary.
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.
I only want to understand the purpose of this change. Is it because DOT was being passed on to the asset rate converter? Or is it to allow things like USDT to be used 1:1 when they come from system parachains?
The asset rate does not know there are different locations of native asset (as in the example in the PR description). And will require a rate to be set for it. With there types we make asset conversion understand different locations of native asset, and do not require a rate to be set for it.
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.
I guess that's one of the problems of marking the difference between the same asset on different chains
Co-authored-by: Branislav Kontur <[email protected]>
Treasury Spend detects the relative locations of native asset to compare origin's spend limits. When a spend is approved for a native asset located on Asset Hub, the AssetRate pallet instance does not recognize the location (parent: 1, here) as a native asset. Therefore, it requires the asset rate to be set in advance to the rate of `1`. To address this issue in this PR, we introduce new types to wrap the `AssetRate` implementation of balance conversion. These types match the native asset's relative locations and result in a 1:1 balance conversion in such cases. In addition we provide integration tests to cover these cases. Examples: Treasury pallet on Relay Chain accepts the spend of the native asset on Asset Hub with it's ID presented as `VersionedLocatableAsset` type ``` { `location`: (0, Parachain(1000)), `asset_id`: (1, Here), } ``` and it's balance should be converted 1:1 by treasury pallet's `BalanceConverter` type. Note: I plan to introduce a similar but configurable implementation in the polkadot-sdk and utilize it here. However, to get this change in the next release, I open this PR first. Frame version: paritytech/polkadot-sdk#3659 --------- Co-authored-by: joe petrowski <[email protected]> Co-authored-by: Branislav Kontur <[email protected]> Co-authored-by: Bastian Köcher <[email protected]>
Review required! Latest push from author must always be reviewed |
location: asset_hub_location.clone(), | ||
asset_id: native_asset.into(), |
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
assert_expected_events!( | ||
AssetHubRococo, | ||
vec![ | ||
RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => {}, |
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.
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 comment
The 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
assert_expected_events!( | ||
Rococo, | ||
vec![ | ||
RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {}, |
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.
Probably the beneficiary of this can be asserted as well
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 does not work right now with this macro
assert_expected_events!( | ||
Westend, | ||
vec![ | ||
RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, |
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.
Could assert the destination
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 does not work right now with this macro
let fellowship_treasury_location: Location = | ||
Location::new(1, [Parachain(1001), PalletInstance(65)]); |
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.
This is the sovereign account in Asset Hub of the fellowship treasury?
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
/// Matches if the given location is a system-level sibling parachain. | ||
pub struct IsSiblingSystemParachain<ParaId, SelfParaId>(PhantomData<(ParaId, SelfParaId)>); | ||
impl<ParaId: IsSystem + From<u32> + Eq, SelfParaId: Get<ParaId>> Contains<Location> | ||
for IsSiblingSystemParachain<ParaId, SelfParaId> | ||
{ | ||
fn contains(l: &Location) -> bool { | ||
matches!( | ||
l.unpack(), | ||
(1, [Junction::Parachain(id)]) | ||
if SelfParaId::get() != ParaId::from(*id) && ParaId::from(*id).is_system(), | ||
) | ||
} | ||
} | ||
|
||
/// Matches if the given location contains only the specified amount of parents and no interior | ||
/// junctions. | ||
pub struct IsParentsOnly<Count>(PhantomData<Count>); | ||
impl<Count: Get<u8>> Contains<Location> for IsParentsOnly<Count> { | ||
fn contains(t: &Location) -> bool { | ||
t.contains_parents_only(Count::get()) | ||
} | ||
} | ||
|
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.
This doesn't look like it should go in barriers.rs
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.
its consistent to what we have in this file, IsChildSystemParachain
just above for example
/// Implements [`ConversionFromAssetBalance`], allowing for a 1:1 balance conversion of the asset | ||
/// when it meets the conditions specified by `C`. If the conditions are not met, the conversion is | ||
/// delegated to `O`. | ||
pub struct UnityOrOuterConversion<C, O>(core::marker::PhantomData<(C, O)>); |
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.
pub struct UnityOrOuterConversion<C, O>(core::marker::PhantomData<(C, O)>); | |
pub struct OneToOneIfElse<C, O>(core::marker::PhantomData<(C, O)>); |
or
pub struct UnityOrOuterConversion<C, O>(core::marker::PhantomData<(C, O)>); | |
pub struct OneToOneOrOuterConversion<C, O>(core::marker::PhantomData<(C, O)>); |
I think it expresses what you want better
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.
we have type above with a name - UnityAssetBalanceConversion
, which also means 1:1. its not wrong and I would keep it consistent.
doc: | ||
- audience: Runtime Dev | ||
description: | | ||
Introduce types to define 1:1 balance conversion for different relative asset ids/locations |
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.
What is the purpose of this change? Should probably mention here to the users what has now changed in how the system is used.
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.
not sure why you mean, this does not changes anything for users, only introduces few new types.
it does changes configuration for westend and rococo chains, but it changes it a way it is expected to work
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.
one nit, I suggest renaming ContainsLatest
to the ContainsAssetFrom
Introduce types to define 1:1 balance conversion for different relative asset ids/locations of native asset.
Examples:
native asset on Asset Hub presented as
VersionedLocatableAsset
type in the context of Relay Chain isand it's balance should be converted 1:1 by implementations of
ConversionToAssetBalance
trait.