Skip to content

Commit

Permalink
bound asset metadata strings (#949)
Browse files Browse the repository at this point in the history
Signed-off-by: Gregory Hill <[email protected]>
  • Loading branch information
gregdhill authored Aug 29, 2023
1 parent d22dc4f commit 7e15fcf
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 53 deletions.
16 changes: 10 additions & 6 deletions asset-registry/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ use xcm_builder::TakeRevenue;
use xcm_executor::{traits::WeightTrader, Assets};

/// Alias for AssetMetadata to improve readability (and to placate clippy)
pub type DefaultAssetMetadata<T> = AssetMetadata<<T as Config>::Balance, <T as Config>::CustomMetadata>;
pub type DefaultAssetMetadata<T> =
AssetMetadata<<T as Config>::Balance, <T as Config>::CustomMetadata, <T as Config>::StringLimit>;

/// An AssetProcessor that assigns a sequential ID
pub struct SequentialId<T>(PhantomData<T>);
Expand Down Expand Up @@ -177,16 +178,19 @@ impl<T: Config> Inspect for Pallet<T> {
type AssetId = T::AssetId;
type Balance = T::Balance;
type CustomMetadata = T::CustomMetadata;
type StringLimit = T::StringLimit;

fn asset_id(location: &MultiLocation) -> Option<Self::AssetId> {
Pallet::<T>::location_to_asset_id(location)
}

fn metadata(id: &Self::AssetId) -> Option<AssetMetadata<Self::Balance, Self::CustomMetadata>> {
fn metadata(id: &Self::AssetId) -> Option<AssetMetadata<Self::Balance, Self::CustomMetadata, Self::StringLimit>> {
Pallet::<T>::metadata(id)
}

fn metadata_by_location(location: &MultiLocation) -> Option<AssetMetadata<Self::Balance, Self::CustomMetadata>> {
fn metadata_by_location(
location: &MultiLocation,
) -> Option<AssetMetadata<Self::Balance, Self::CustomMetadata, Self::StringLimit>> {
Pallet::<T>::fetch_metadata_by_location(location)
}

Expand All @@ -198,16 +202,16 @@ impl<T: Config> Inspect for Pallet<T> {
impl<T: Config> Mutate for Pallet<T> {
fn register_asset(
asset_id: Option<Self::AssetId>,
metadata: AssetMetadata<Self::Balance, Self::CustomMetadata>,
metadata: AssetMetadata<Self::Balance, Self::CustomMetadata, Self::StringLimit>,
) -> DispatchResult {
Pallet::<T>::do_register_asset(metadata, asset_id)
}

fn update_asset(
asset_id: Self::AssetId,
decimals: Option<u32>,
name: Option<Vec<u8>>,
symbol: Option<Vec<u8>>,
name: Option<BoundedVec<u8, Self::StringLimit>>,
symbol: Option<BoundedVec<u8, Self::StringLimit>>,
existential_deposit: Option<Self::Balance>,
location: Option<Option<VersionedMultiLocation>>,
additional: Option<Self::CustomMetadata>,
Expand Down
47 changes: 30 additions & 17 deletions asset-registry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,27 @@ pub mod module {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

/// Additional non-standard metadata to store for each asset
type CustomMetadata: Parameter + Member + TypeInfo;
type CustomMetadata: Parameter + Member + TypeInfo + MaxEncodedLen;

/// The type used as a unique asset id,
type AssetId: Parameter + Member + Default + TypeInfo + MaybeSerializeDeserialize;
type AssetId: Parameter + Member + Default + TypeInfo + MaybeSerializeDeserialize + MaxEncodedLen;

/// Checks that an origin has the authority to register/update an asset
type AuthorityOrigin: EnsureOriginWithArg<Self::RuntimeOrigin, Option<Self::AssetId>>;

/// A filter ran upon metadata registration that assigns an is and
/// potentially modifies the supplied metadata.
type AssetProcessor: AssetProcessor<Self::AssetId, AssetMetadata<Self::Balance, Self::CustomMetadata>>;
type AssetProcessor: AssetProcessor<
Self::AssetId,
AssetMetadata<Self::Balance, Self::CustomMetadata, Self::StringLimit>,
>;

/// The balance type.
type Balance: Parameter + Member + AtLeast32BitUnsigned + Default + Copy;
type Balance: Parameter + Member + AtLeast32BitUnsigned + Default + Copy + MaxEncodedLen;

/// The maximum length of a name or symbol.
#[pallet::constant]
type StringLimit: Get<u32>;

/// Weight information for extrinsics in this module.
type WeightInfo: WeightInfo;
Expand All @@ -72,26 +79,33 @@ pub mod module {
ConflictingLocation,
/// Another asset was already register with this asset id.
ConflictingAssetId,
/// Name or symbol is too long.
InvalidAssetString,
}

#[pallet::event]
#[pallet::generate_deposit(pub(crate) fn deposit_event)]
pub enum Event<T: Config> {
RegisteredAsset {
asset_id: T::AssetId,
metadata: AssetMetadata<T::Balance, T::CustomMetadata>,
metadata: AssetMetadata<T::Balance, T::CustomMetadata, T::StringLimit>,
},
UpdatedAsset {
asset_id: T::AssetId,
metadata: AssetMetadata<T::Balance, T::CustomMetadata>,
metadata: AssetMetadata<T::Balance, T::CustomMetadata, T::StringLimit>,
},
}

/// The metadata of an asset, indexed by asset id.
#[pallet::storage]
#[pallet::getter(fn metadata)]
pub type Metadata<T: Config> =
StorageMap<_, Twox64Concat, T::AssetId, AssetMetadata<T::Balance, T::CustomMetadata>, OptionQuery>;
pub type Metadata<T: Config> = StorageMap<
_,
Twox64Concat,
T::AssetId,
AssetMetadata<T::Balance, T::CustomMetadata, T::StringLimit>,
OptionQuery,
>;

/// Maps a multilocation to an asset id - useful when processing xcm
/// messages.
Expand Down Expand Up @@ -136,7 +150,6 @@ pub mod module {

#[pallet::pallet]
#[pallet::storage_version(STORAGE_VERSION)]
#[pallet::without_storage_info]
pub struct Pallet<T>(_);

#[pallet::call]
Expand All @@ -145,7 +158,7 @@ pub mod module {
#[pallet::weight(T::WeightInfo::register_asset())]
pub fn register_asset(
origin: OriginFor<T>,
metadata: AssetMetadata<T::Balance, T::CustomMetadata>,
metadata: AssetMetadata<T::Balance, T::CustomMetadata, T::StringLimit>,
asset_id: Option<T::AssetId>,
) -> DispatchResult {
T::AuthorityOrigin::ensure_origin(origin, &asset_id)?;
Expand All @@ -159,8 +172,8 @@ pub mod module {
origin: OriginFor<T>,
asset_id: T::AssetId,
decimals: Option<u32>,
name: Option<Vec<u8>>,
symbol: Option<Vec<u8>>,
name: Option<BoundedVec<u8, T::StringLimit>>,
symbol: Option<BoundedVec<u8, T::StringLimit>>,
existential_deposit: Option<T::Balance>,
location: Option<Option<VersionedMultiLocation>>,
additional: Option<T::CustomMetadata>,
Expand All @@ -185,7 +198,7 @@ pub mod module {
impl<T: Config> Pallet<T> {
/// Register a new asset
pub fn do_register_asset(
metadata: AssetMetadata<T::Balance, T::CustomMetadata>,
metadata: AssetMetadata<T::Balance, T::CustomMetadata, T::StringLimit>,
asset_id: Option<T::AssetId>,
) -> DispatchResult {
let (asset_id, metadata) = T::AssetProcessor::pre_register(asset_id, metadata)?;
Expand All @@ -202,7 +215,7 @@ impl<T: Config> Pallet<T> {
/// This function is useful in tests but it might also come in useful to
/// users.
pub fn do_register_asset_without_asset_processor(
metadata: AssetMetadata<T::Balance, T::CustomMetadata>,
metadata: AssetMetadata<T::Balance, T::CustomMetadata, T::StringLimit>,
asset_id: T::AssetId,
) -> DispatchResult {
Metadata::<T>::try_mutate(&asset_id, |maybe_metadata| -> DispatchResult {
Expand All @@ -226,8 +239,8 @@ impl<T: Config> Pallet<T> {
pub fn do_update_asset(
asset_id: T::AssetId,
decimals: Option<u32>,
name: Option<Vec<u8>>,
symbol: Option<Vec<u8>>,
name: Option<BoundedVec<u8, T::StringLimit>>,
symbol: Option<BoundedVec<u8, T::StringLimit>>,
existential_deposit: Option<T::Balance>,
location: Option<Option<VersionedMultiLocation>>,
additional: Option<T::CustomMetadata>,
Expand Down Expand Up @@ -272,7 +285,7 @@ impl<T: Config> Pallet<T> {

pub fn fetch_metadata_by_location(
location: &MultiLocation,
) -> Option<AssetMetadata<T::Balance, T::CustomMetadata>> {
) -> Option<AssetMetadata<T::Balance, T::CustomMetadata, T::StringLimit>> {
let asset_id = LocationToAssetId::<T>::get(location)?;
Metadata::<T>::get(asset_id)
}
Expand Down
12 changes: 6 additions & 6 deletions asset-registry/src/mock/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,10 @@ decl_test_parachain! {
new_ext = para_ext(4, Some((
vec![(
4,
AssetMetadata::<Balance, para::CustomMetadata>::encode(&AssetMetadata {
AssetMetadata::<Balance, para::CustomMetadata, para::StringLimit>::encode(&AssetMetadata {
decimals: 12,
name: "para G native token".as_bytes().to_vec(),
symbol: "paraG".as_bytes().to_vec(),
name: BoundedVec::truncate_from("para G native token".as_bytes().to_vec()),
symbol: BoundedVec::truncate_from("paraG".as_bytes().to_vec()),
existential_deposit: 0,
location: None,
additional: para::CustomMetadata {
Expand All @@ -194,10 +194,10 @@ decl_test_parachain! {
})),
(
5,
AssetMetadata::<Balance, para::CustomMetadata>::encode(&AssetMetadata {
AssetMetadata::<Balance, para::CustomMetadata, para::StringLimit>::encode(&AssetMetadata {
decimals: 12,
name: "para G foreign token".as_bytes().to_vec(),
symbol: "paraF".as_bytes().to_vec(),
name: BoundedVec::truncate_from("para G foreign token".as_bytes().to_vec()),
symbol: BoundedVec::truncate_from("paraF".as_bytes().to_vec()),
existential_deposit: 0,
location: None,
additional: para::CustomMetadata {
Expand Down
9 changes: 7 additions & 2 deletions asset-registry/src/mock/para.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::{Amount, Balance, CurrencyId, CurrencyIdConvert, ParachainXcmRouter};

use crate as orml_asset_registry;

use codec::{Decode, Encode};
use codec::{Decode, Encode, MaxEncodedLen};
use cumulus_primitives_core::{ChannelStatus, GetChannelInfo, ParaId};
use frame_support::traits::{EnsureOrigin, EnsureOriginWithArg};
use frame_support::{
Expand Down Expand Up @@ -101,7 +101,7 @@ impl orml_tokens::Config for Runtime {
type DustRemovalWhitelist = Nothing;
}

#[derive(scale_info::TypeInfo, Encode, Decode, Clone, Eq, PartialEq, Debug)]
#[derive(scale_info::TypeInfo, Encode, Decode, Clone, Eq, PartialEq, Debug, MaxEncodedLen)]
pub struct CustomMetadata {
pub fee_per_second: u128,
}
Expand Down Expand Up @@ -138,13 +138,18 @@ impl EnsureOriginWithArg<RuntimeOrigin, Option<u32>> for AssetAuthority {

pub type ParaAssetId = u32;

parameter_types! {
pub const StringLimit: u32 = 50;
}

impl orml_asset_registry::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Balance = Balance;
type AssetId = ParaAssetId;
type AuthorityOrigin = AssetAuthority;
type CustomMetadata = CustomMetadata;
type AssetProcessor = orml_asset_registry::SequentialId<Runtime>;
type StringLimit = StringLimit;
type WeightInfo = ();
}

Expand Down
81 changes: 70 additions & 11 deletions asset-registry/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,15 @@ fn print_events<Runtime: frame_system::Config>(name: &'static str) {
.for_each(|r| println!("> {:?}", r.event));
}

fn dummy_metadata() -> AssetMetadata<<para::Runtime as orml_asset_registry::Config>::Balance, CustomMetadata> {
fn dummy_metadata() -> AssetMetadata<
<para::Runtime as orml_asset_registry::Config>::Balance,
CustomMetadata,
<para::Runtime as orml_asset_registry::Config>::StringLimit,
> {
AssetMetadata {
decimals: 12,
name: "para A native token".as_bytes().to_vec(),
symbol: "paraA".as_bytes().to_vec(),
name: BoundedVec::truncate_from("para A native token".as_bytes().to_vec()),
symbol: BoundedVec::truncate_from("paraA".as_bytes().to_vec()),
existential_deposit: 0,
location: Some(
MultiLocation::new(
Expand All @@ -75,8 +79,8 @@ fn genesis_issuance_should_work() {
ParaG::execute_with(|| {
let metadata1 = AssetMetadata {
decimals: 12,
name: "para G native token".as_bytes().to_vec(),
symbol: "paraG".as_bytes().to_vec(),
name: BoundedVec::truncate_from("para G native token".as_bytes().to_vec()),
symbol: BoundedVec::truncate_from("paraG".as_bytes().to_vec()),
existential_deposit: 0,
location: None,
additional: CustomMetadata {
Expand All @@ -85,8 +89,8 @@ fn genesis_issuance_should_work() {
};
let metadata2 = AssetMetadata {
decimals: 12,
name: "para G foreign token".as_bytes().to_vec(),
symbol: "paraF".as_bytes().to_vec(),
name: BoundedVec::truncate_from("para G foreign token".as_bytes().to_vec()),
symbol: BoundedVec::truncate_from("paraF".as_bytes().to_vec()),
existential_deposit: 0,
location: None,
additional: CustomMetadata {
Expand Down Expand Up @@ -265,8 +269,8 @@ fn test_sequential_id_normal_behavior() {
let metadata1 = dummy_metadata();

let metadata2 = AssetMetadata {
name: "para A native token 2".as_bytes().to_vec(),
symbol: "paraA2".as_bytes().to_vec(),
name: BoundedVec::truncate_from("para A native token 2".as_bytes().to_vec()),
symbol: BoundedVec::truncate_from("paraA2".as_bytes().to_vec()),
location: Some(
MultiLocation::new(
1,
Expand Down Expand Up @@ -463,8 +467,8 @@ fn test_update_metadata_works() {

let new_metadata = AssetMetadata {
decimals: 11,
name: "para A native token2".as_bytes().to_vec(),
symbol: "paraA2".as_bytes().to_vec(),
name: BoundedVec::truncate_from("para A native token2".as_bytes().to_vec()),
symbol: BoundedVec::truncate_from("paraA2".as_bytes().to_vec()),
existential_deposit: 1,
location: Some(
MultiLocation::new(
Expand Down Expand Up @@ -711,3 +715,58 @@ fn from_unversioned_to_v2_storage() {
assert_eq!(crate::Migration::<para::Runtime>::on_runtime_upgrade(), Weight::zero());
});
}

#[test]
fn test_decode_bounded_vec() {
TestNet::reset();

pub mod unbounded {
use super::*;

#[frame_support::storage_alias]
pub type Metadata<T: orml_asset_registry::Config> = StorageMap<
orml_asset_registry::Pallet<T>,
Twox64Concat,
<T as orml_asset_registry::Config>::AssetId,
AssetMetadata<
<T as orml_asset_registry::Config>::Balance,
<T as orml_asset_registry::Config>::CustomMetadata,
>,
OptionQuery,
>;

#[derive(TypeInfo, Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug)]
pub struct AssetMetadata<Balance, CustomMetadata: Parameter + Member + TypeInfo> {
pub decimals: u32,
pub name: Vec<u8>,
pub symbol: Vec<u8>,
pub existential_deposit: Balance,
pub location: Option<VersionedMultiLocation>,
pub additional: CustomMetadata,
}
}

ParaA::execute_with(|| {
let para_name = "para A native token".as_bytes().to_vec();
let para_symbol = "paraA".as_bytes().to_vec();
unbounded::Metadata::<para::Runtime>::insert(
0,
unbounded::AssetMetadata {
decimals: 12,
name: para_name.clone(),
symbol: para_symbol.clone(),
existential_deposit: 0,
location: None,
additional: CustomMetadata {
fee_per_second: 1_000_000_000_000,
},
},
);

let asset_metadata = Metadata::<para::Runtime>::get(0);
assert_eq!(
asset_metadata.map(|m| (m.name.to_vec(), m.symbol.to_vec())),
Some((para_name, para_symbol))
);
});
}
Loading

0 comments on commit 7e15fcf

Please sign in to comment.