-
Notifications
You must be signed in to change notification settings - Fork 1.1k
[pallet-assets] add ForeignAssetIdExtractor to assets precompile #10869
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
base: master
Are you sure you want to change the base?
Changes from all commits
dc1b49d
01bc26f
4881b06
e1aed98
518483d
6d83853
4f0d2da
03c1bd4
1b3ba4f
9623664
8f9530c
06b9f65
99a6617
bf81f0b
3a828f1
aeb3994
c5c92d7
20b06a0
c90d1f9
8137af0
749909b
5acbcd0
407c3ab
7ac170f
d3f3ee1
50a8fe2
166086b
32ac7af
5f78f44
d557688
9fb29b6
6a7df21
85d07e5
7e5646e
4558a0c
b512057
4093bf1
3166112
a5469d7
c9175e7
98d5544
8f59004
31b04ed
2b7b273
bc74d06
a4e3390
26cad5c
6971006
a167412
906d510
a4df7bc
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 |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| title: '[pallet-assets] add ForeignAssetIdExtractor to assets precompile' | ||
| doc: | ||
| - audience: Runtime Dev | ||
| description: |- | ||
| Fixes https://github.com/paritytech/polkadot-sdk/issues/8659 | ||
|
|
||
| Implements `ForeignAssetIdExtractor` trait for pallet-assets-precompiles that enables conversion of u32 asset IDs to XCM Location types. This allows smart contracts to interact with foreign assets through a standardized interface. | ||
|
|
||
| Key additions: | ||
| - `ForeignAssetIdExtractor` implementation for converting asset indices to foreign asset IDs | ||
| - Indexing mechanism via `AssetIndexToForeignAssetId` storage to map u32 indices to location-based asset IDs | ||
| - created new pallet for holding the StorageMaps: pallet-assets-precompiles. | ||
| - Validation logic to prevent hash collisions during asset index registration | ||
| - Integration with asset-hub-westend runtime | ||
|
|
||
| crates: | ||
| - name: pallet-assets | ||
| bump: minor | ||
| - name: pallet-assets-precompiles | ||
| bump: minor | ||
| - name: asset-hub-westend-runtime | ||
| bump: minor | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| // This file is part of Substrate. | ||
|
|
||
| // 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 core::marker::PhantomData; | ||
| use frame_support::LOG_TARGET; | ||
| use pallet_assets::AssetsCallback; | ||
|
|
||
| pub use pallet::*; | ||
|
|
||
| pub struct ForeignAssetId<T, I = ()>(PhantomData<(T, I)>); | ||
| impl<T: Config, I> AssetsCallback<T::AssetId, T::AccountId> for ForeignAssetId<T, I> | ||
| where | ||
| T: Config<ForeignAssetId = T::AssetId> + pallet_assets::Config<I>, | ||
| I: 'static, | ||
| { | ||
| fn created(id: &T::AssetId, _: &T::AccountId) -> Result<(), ()> { | ||
0xRVE marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Pallet::<T>::insert_asset_mapping(id).map(|_| ()) | ||
| } | ||
|
|
||
| fn destroyed(id: &T::AssetId) -> Result<(), ()> { | ||
| Pallet::<T>::remove_asset_mapping(id); | ||
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
| #[frame_support::pallet] | ||
| pub mod pallet { | ||
| use super::*; | ||
| use frame_support::{pallet_prelude::*, Blake2_128Concat}; | ||
|
|
||
| #[pallet::config] | ||
| pub trait Config: frame_system::Config { | ||
| /// The foreign asset ID type. This must match the `AssetId` type used by the | ||
| /// `pallet_assets` instance for foreign assets. | ||
| type ForeignAssetId: Member + Parameter + Clone + MaybeSerializeDeserialize + MaxEncodedLen; | ||
|
Contributor
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. I really think we should simplify where we can and not use an associated type here where we can hardcode it to Location, will test what it looks like without it
Contributor
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. @franciscoaguirre what do you think ? or maybe it's annoying because we need to update the Location version everytime you bump it here
Contributor
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. tasked Claude with it here #10945 |
||
| } | ||
|
|
||
| #[pallet::pallet] | ||
| pub struct Pallet<T>(_); | ||
|
|
||
| /// The next available asset index for foreign assets. | ||
|
Contributor
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. I don't think we need anything pub in this pallet, all we need is the AssetsCallback and the ForeignAssetIdExtractor that I will keep in that module to keep everything private
Contributor
Author
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. Was able to remove a few pubs |
||
| /// This is incremented each time a new foreign asset mapping is created. | ||
| #[pallet::storage] | ||
| pub type NextAssetIndex<T: Config> = StorageValue<_, u32, ValueQuery>; | ||
|
|
||
| /// Mapping an asset index (derived from the precompile address) to a `ForeignAssetId`. | ||
| #[pallet::storage] | ||
| pub type AssetIndexToForeignAssetId<T: Config> = | ||
| StorageMap<_, Identity, u32, T::ForeignAssetId, OptionQuery>; | ||
|
|
||
| /// Mapping a `ForeignAssetId` to an asset index (used for deriving precompile addresses). | ||
| #[pallet::storage] | ||
| pub type ForeignAssetIdToAssetIndex<T: Config> = | ||
| StorageMap<_, Blake2_128Concat, T::ForeignAssetId, u32, OptionQuery>; | ||
|
|
||
| impl<T: Config> Pallet<T> { | ||
| /// Get the foreign asset ID for a given asset index. | ||
| pub fn asset_id_of(asset_index: u32) -> Option<T::ForeignAssetId> { | ||
| AssetIndexToForeignAssetId::<T>::get(asset_index) | ||
| } | ||
|
|
||
| /// Get the asset index for a given foreign asset ID. | ||
| pub fn asset_index_of(asset_id: &T::ForeignAssetId) -> Option<u32> { | ||
| ForeignAssetIdToAssetIndex::<T>::get(asset_id) | ||
| } | ||
|
|
||
| /// Get the next available asset index without incrementing it. | ||
| pub fn next_asset_index() -> u32 { | ||
| NextAssetIndex::<T>::get() | ||
| } | ||
|
|
||
| /// Insert a new asset mapping, allocating a sequential index. | ||
| /// Returns the allocated asset index on success. | ||
| pub fn insert_asset_mapping(asset_id: &T::ForeignAssetId) -> Result<u32, ()> { | ||
| if ForeignAssetIdToAssetIndex::<T>::contains_key(asset_id) { | ||
| log::error!(target: LOG_TARGET, "Asset id {:?} already mapped", asset_id); | ||
| return Err(()); | ||
| } | ||
|
|
||
| let asset_index = NextAssetIndex::<T>::get(); | ||
| let next_index = asset_index.checked_add(1).ok_or_else(|| { | ||
| log::error!(target: LOG_TARGET, "Asset index overflow"); | ||
| () | ||
| })?; | ||
|
|
||
| AssetIndexToForeignAssetId::<T>::insert(asset_index, asset_id.clone()); | ||
| ForeignAssetIdToAssetIndex::<T>::insert(asset_id, asset_index); | ||
| NextAssetIndex::<T>::put(next_index); | ||
|
|
||
| log::debug!(target: LOG_TARGET, "Mapped asset {:?} to index {:?}", asset_id, asset_index); | ||
| Ok(asset_index) | ||
| } | ||
|
|
||
| pub fn remove_asset_mapping(asset_id: &T::ForeignAssetId) { | ||
| if let Some(asset_index) = ForeignAssetIdToAssetIndex::<T>::get(&asset_id) { | ||
| AssetIndexToForeignAssetId::<T>::remove(asset_index); | ||
| ForeignAssetIdToAssetIndex::<T>::remove(asset_id); | ||
| } | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.