diff --git a/Cargo.lock b/Cargo.lock index b71802415a..bc81d78906 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8416,10 +8416,10 @@ dependencies = [ [[package]] name = "sc-consensus-uncles" version = "0.9.0" -source = "git+https://github.com/paritytech//substrate?rev=1d04678e20555e623c974ee1127bc8a45abcf3d6#1d04678e20555e623c974ee1127bc8a45abcf3d6" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.4#1d04678e20555e623c974ee1127bc8a45abcf3d6" dependencies = [ "sc-client-api", - "sp-authorship 3.0.0 (git+https://github.com/paritytech//substrate?rev=1d04678e20555e623c974ee1127bc8a45abcf3d6)", + "sp-authorship 3.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.4)", "sp-runtime", "thiserror", ] @@ -8427,10 +8427,10 @@ dependencies = [ [[package]] name = "sc-consensus-uncles" version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.4#1d04678e20555e623c974ee1127bc8a45abcf3d6" +source = "git+https://github.com/paritytech//substrate?rev=1d04678e20555e623c974ee1127bc8a45abcf3d6#1d04678e20555e623c974ee1127bc8a45abcf3d6" dependencies = [ "sc-client-api", - "sp-authorship 3.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.4)", + "sp-authorship 3.0.0 (git+https://github.com/paritytech//substrate?rev=1d04678e20555e623c974ee1127bc8a45abcf3d6)", "sp-runtime", "thiserror", ] @@ -8640,7 +8640,7 @@ dependencies = [ [[package]] name = "sc-light" version = "3.0.0" -source = "git+https://github.com/paritytech//substrate?rev=1d04678e20555e623c974ee1127bc8a45abcf3d6#1d04678e20555e623c974ee1127bc8a45abcf3d6" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.4#1d04678e20555e623c974ee1127bc8a45abcf3d6" dependencies = [ "hash-db", "lazy_static", @@ -8659,7 +8659,7 @@ dependencies = [ [[package]] name = "sc-light" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.4#1d04678e20555e623c974ee1127bc8a45abcf3d6" +source = "git+https://github.com/paritytech//substrate?rev=1d04678e20555e623c974ee1127bc8a45abcf3d6#1d04678e20555e623c974ee1127bc8a45abcf3d6" dependencies = [ "hash-db", "lazy_static", @@ -9568,7 +9568,7 @@ dependencies = [ [[package]] name = "sp-authorship" version = "3.0.0" -source = "git+https://github.com/paritytech//substrate?rev=1d04678e20555e623c974ee1127bc8a45abcf3d6#1d04678e20555e623c974ee1127bc8a45abcf3d6" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.4#1d04678e20555e623c974ee1127bc8a45abcf3d6" dependencies = [ "async-trait", "parity-scale-codec", @@ -9580,7 +9580,7 @@ dependencies = [ [[package]] name = "sp-authorship" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.4#1d04678e20555e623c974ee1127bc8a45abcf3d6" +source = "git+https://github.com/paritytech//substrate?rev=1d04678e20555e623c974ee1127bc8a45abcf3d6#1d04678e20555e623c974ee1127bc8a45abcf3d6" dependencies = [ "async-trait", "parity-scale-codec", @@ -9850,7 +9850,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "3.0.0" -source = "git+https://github.com/paritytech//substrate?rev=1d04678e20555e623c974ee1127bc8a45abcf3d6#1d04678e20555e623c974ee1127bc8a45abcf3d6" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.4#1d04678e20555e623c974ee1127bc8a45abcf3d6" dependencies = [ "lazy_static", "sp-core", @@ -9861,7 +9861,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.4#1d04678e20555e623c974ee1127bc8a45abcf3d6" +source = "git+https://github.com/paritytech//substrate?rev=1d04678e20555e623c974ee1127bc8a45abcf3d6#1d04678e20555e623c974ee1127bc8a45abcf3d6" dependencies = [ "lazy_static", "sp-core", diff --git a/pallets/asset-index/src/benchmarking.rs b/pallets/asset-index/src/benchmarking.rs index 016a2475a5..dec5c25807 100644 --- a/pallets/asset-index/src/benchmarking.rs +++ b/pallets/asset-index/src/benchmarking.rs @@ -9,7 +9,7 @@ use xcm::v0::MultiLocation; benchmarks! { add_asset { - let asset_id = 42.into(); + let asset_id = 42_u32.into(); let caller: T::AccountId = whitelisted_caller(); let million = 1_000_000u32.into(); T::IndexToken::deposit_creating(&caller, million); @@ -28,4 +28,22 @@ benchmarks! { )) ); } + + set_metadata { + let asset_id = 0_u32.into(); + let name = b"pint".to_vec(); + let symbol = b"pint".to_vec(); + let decimals = 8_u8; + }: _( + RawOrigin::Signed(whitelisted_caller()), + asset_id, + name.clone(), + symbol.clone(), + decimals + ) verify { + let metadata = >::get(asset_id); + assert_eq!(metadata.name.as_slice(), name.as_slice()); + assert_eq!(metadata.symbol.as_slice(), symbol.as_slice()); + assert_eq!(metadata.decimals, decimals); + } } diff --git a/pallets/asset-index/src/lib.rs b/pallets/asset-index/src/lib.rs index fe0d19f2d4..00c43ab37e 100644 --- a/pallets/asset-index/src/lib.rs +++ b/pallets/asset-index/src/lib.rs @@ -18,7 +18,7 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; pub mod traits; -mod types; +pub mod types; #[frame_support::pallet] // this is requires as the #[pallet::event] proc macro generates code that violates this lint @@ -49,7 +49,8 @@ pub mod pallet { pub use crate::traits::{AssetRecorder, MultiAssetRegistry}; pub use crate::types::MultiAssetAdapter; use crate::types::{ - AssetAvailability, AssetWithdrawal, IndexAssetData, PendingRedemption, RedemptionState, + AssetAvailability, AssetMetadata, AssetWithdrawal, IndexAssetData, PendingRedemption, + RedemptionState, }; type AccountIdFor = ::AccountId; @@ -91,7 +92,7 @@ pub mod pallet { Self::Balance, >; /// Type used to identify assets - type AssetId: Parameter + Member + From + Copy; + type AssetId: Parameter + Member + AtLeast32BitUnsigned + Copy; /// Handles asset depositing and withdrawing from sovereign user accounts type MultiAssetDepository: MultiAssetDepository< Self::AssetId, @@ -107,6 +108,9 @@ pub mod pallet { type TreasuryPalletId: Get; type Event: From> + IsType<::Event>; + /// The maximum length of a name or symbol stored on-chain. + type StringLimit: Get; + /// The weight for this pallet's extrinsics. type WeightInfo: WeightInfo; } @@ -130,6 +134,18 @@ pub mod pallet { OptionQuery, >; + #[pallet::storage] + /// Metadata of an asset ( for reversed usage now ). + pub(super) type Metadata = StorageMap< + _, + Blake2_128Concat, + T::AssetId, + AssetMetadata>, + ValueQuery, + GetDefault, + ConstU32<300_000>, + >; + #[pallet::event] #[pallet::metadata(T::AssetId = "AccountId", AccountIdFor < T > = "AccountId", T::Balance = "Balance")] #[pallet::generate_deposit(pub (super) fn deposit_event)] @@ -152,12 +168,18 @@ pub mod pallet { AccountIdFor, Vec>, ), + /// New metadata has been set for an asset. \[asset_id, name, symbol, decimals\] + MetadataSet(T::AssetId, Vec, Vec, u8), } #[pallet::error] pub enum Error { /// Thrown if adding units to an asset holding causes its numerical type to overflow AssetUnitsOverflow, + /// The given asset ID is unknown. + UnknownAsset, + /// Invalid metadata given. + BadMetadata, /// Thrown if no index could be found for an asset identifier. UnsupportedAsset, /// Thrown if calculating the volume of units of an asset with it's price overflows. @@ -207,6 +229,51 @@ pub mod pallet { Ok(().into()) } + /// Force the metadata for an asset to some value. + /// + /// Origin must be ForceOrigin. + /// + /// Any deposit is left alone. + /// + /// - `id`: The identifier of the asset to update. + /// - `name`: The user friendly name of this asset. Limited in length by `StringLimit`. + /// - `symbol`: The exchange symbol for this asset. Limited in length by `StringLimit`. + /// - `decimals`: The number of decimals this asset uses to represent one unit. + /// + /// Emits `MetadataSet`. + /// + /// Weight: `O(N + S)` where N and S are the length of the name and symbol respectively. + #[pallet::weight(T::WeightInfo::add_asset())] + pub fn set_metadata( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, + name: Vec, + symbol: Vec, + decimals: u8, + ) -> DispatchResult { + T::AdminOrigin::ensure_origin(origin)?; + + let bounded_name: BoundedVec = name + .clone() + .try_into() + .map_err(|_| >::BadMetadata)?; + let bounded_symbol: BoundedVec = symbol + .clone() + .try_into() + .map_err(|_| >::BadMetadata)?; + + >::try_mutate_exists(id, |metadata| { + *metadata = Some(AssetMetadata { + name: bounded_name, + symbol: bounded_symbol, + decimals, + }); + + Self::deposit_event(Event::MetadataSet(id, name, symbol, decimals)); + Ok(()) + }) + } + /// Initiate a transfer from the user's sovereign account into the index. /// /// This will withdraw the given amount from the user's sovereign account and mints PINT @@ -568,6 +635,7 @@ pub mod pallet { /// Trait for the asset-index pallet extrinsic weights. pub trait WeightInfo { fn add_asset() -> Weight; + fn set_metadata() -> Weight; } /// For backwards compatibility and tests @@ -575,5 +643,9 @@ pub mod pallet { fn add_asset() -> Weight { Default::default() } + + fn set_metadata() -> Weight { + Default::default() + } } } diff --git a/pallets/asset-index/src/mock.rs b/pallets/asset-index/src/mock.rs index cd94cf650c..e7924ff59f 100644 --- a/pallets/asset-index/src/mock.rs +++ b/pallets/asset-index/src/mock.rs @@ -123,6 +123,7 @@ parameter_types! { pub WithdrawalPeriod: ::BlockNumber = 10; pub DOTContributionLimit: Balance = 999; pub TreasuryPalletId: PalletId = PalletId(*b"12345678"); + pub StringLimit: u32 = 4; } impl pallet_asset_index::Config for Test { @@ -139,6 +140,7 @@ impl pallet_asset_index::Config for Test { type MultiAssetDepository = AssetDepository; type PriceFeed = MockPriceFeed; type TreasuryPalletId = TreasuryPalletId; + type StringLimit = StringLimit; type WithdrawalFee = (); type WeightInfo = (); } diff --git a/pallets/asset-index/src/tests.rs b/pallets/asset-index/src/tests.rs index 54187e855b..f4c07ec2cc 100644 --- a/pallets/asset-index/src/tests.rs +++ b/pallets/asset-index/src/tests.rs @@ -87,6 +87,66 @@ fn admin_can_add_asset_twice_and_units_accumulate() { }); } +#[test] +fn non_admin_cannot_set_metadata() { + new_test_ext(vec![]).execute_with(|| { + assert_noop!( + AssetIndex::set_metadata( + Origin::signed(ASHLEY), + ASSET_A_ID, + b"dot".to_vec(), + b"dot".to_vec(), + 8, + ), + BadOrigin + ); + }); +} + +#[test] +fn admin_can_set_metadata() { + new_test_ext(vec![]).execute_with(|| { + assert_ok!(AssetIndex::set_metadata( + Origin::signed(ADMIN_ACCOUNT_ID), + ASSET_A_ID, + b"dot".to_vec(), + b"dot".to_vec(), + 8, + )); + }); +} + +#[test] +fn admin_can_update_metadata() { + new_test_ext(vec![]).execute_with(|| { + assert_ok!(AssetIndex::set_metadata( + Origin::signed(ADMIN_ACCOUNT_ID), + ASSET_A_ID, + b"dot".to_vec(), + b"dot".to_vec(), + 8, + )); + + assert_eq!( + >::get(ASSET_A_ID).name, + b"dot".to_vec() + ); + + assert_ok!(AssetIndex::set_metadata( + Origin::signed(ADMIN_ACCOUNT_ID), + ASSET_A_ID, + b"pint".to_vec(), + b"pint".to_vec(), + 8, + )); + + assert_eq!( + >::get(ASSET_A_ID).name, + b"pint".to_vec() + ); + }); +} + #[test] fn deposit_only_works_for_added_liquid_assets() { let initial_balances: Vec<(AccountId, Balance)> = vec![(ADMIN_ACCOUNT_ID, 0)]; @@ -148,6 +208,13 @@ fn deposit_works_with_user_balance() { fn deposit_fails_for_unknown_assets() { let initial_balances: Vec<(AccountId, Balance)> = vec![(ADMIN_ACCOUNT_ID, 0)]; new_test_ext(initial_balances).execute_with(|| { + assert_ok!(AssetIndex::add_asset( + Origin::signed(ADMIN_ACCOUNT_ID), + ASSET_A_ID, + 100, + AssetAvailability::Liquid(MultiLocation::Null), + 5 + )); assert_noop!( AssetIndex::deposit(Origin::signed(ASHLEY), UNKNOWN_ASSET_ID, 1_000), pallet::Error::::UnsupportedAsset diff --git a/pallets/asset-index/src/traits.rs b/pallets/asset-index/src/traits.rs index c26bcd61ea..af90736b40 100644 --- a/pallets/asset-index/src/traits.rs +++ b/pallets/asset-index/src/traits.rs @@ -1,9 +1,8 @@ // Copyright 2021 ChainSafe Systems // SPDX-License-Identifier: LGPL-3.0-only -pub use crate::types::AssetAvailability; -use frame_support::dispatch::DispatchResult; -use frame_support::sp_runtime::traits::AtLeast32BitUnsigned; +pub use crate::types::{AssetAvailability, AssetMetadata}; +use frame_support::{dispatch::DispatchResult, sp_runtime::traits::AtLeast32BitUnsigned}; use xcm::v0::MultiLocation; pub trait AssetRecorder { diff --git a/pallets/asset-index/src/types.rs b/pallets/asset-index/src/types.rs index 25dcdac3b6..485da04b0e 100644 --- a/pallets/asset-index/src/types.rs +++ b/pallets/asset-index/src/types.rs @@ -33,6 +33,14 @@ pub enum AssetAvailability { Saft, } +/// Metadata for an asset +#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, RuntimeDebug)] +pub struct AssetMetadata { + pub name: BoundedString, + pub symbol: BoundedString, + pub decimals: u8, +} + #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] /// A representation of some number of assets that are managed by the index pub struct IndexAssetData { diff --git a/pallets/saft-registry/src/benchmarking.rs b/pallets/saft-registry/src/benchmarking.rs index 0850d6d9f0..af200ff412 100644 --- a/pallets/saft-registry/src/benchmarking.rs +++ b/pallets/saft-registry/src/benchmarking.rs @@ -36,7 +36,12 @@ benchmarks! { // } report_nav { - assert_ok!(>::add_saft(>::Root.into(), 0.into(), 100_u32.into(), 20_u32.into())); + assert_ok!(>::add_saft( + >::Root.into(), + 0.into(), + 100_u32.into(), + 20_u32.into(), + )); }: _( >::Root, 0.into(), diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index b70a3c142a..3e9490f79c 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -617,6 +617,7 @@ parameter_types! { pub MinimumRedemption: u32 = 0; pub WithdrawalPeriod: ::BlockNumber = 10; pub DOTContributionLimit: Balance = 999; + pub PalletIndexStringLimit: u32 = 50; } impl pallet_asset_index::Config for Runtime { @@ -635,6 +636,7 @@ impl pallet_asset_index::Config for Runtime { type PriceFeed = PriceFeed; type TreasuryPalletId = TreasuryPalletId; type WithdrawalFee = (); + type StringLimit = PalletIndexStringLimit; type WeightInfo = weights::pallet_asset_index::WeightInfo; } diff --git a/runtime/src/weights/pallet_asset_index.rs b/runtime/src/weights/pallet_asset_index.rs index 50a994aeb9..cb2b1c78f2 100644 --- a/runtime/src/weights/pallet_asset_index.rs +++ b/runtime/src/weights/pallet_asset_index.rs @@ -4,8 +4,8 @@ //! Autogenerated weights for pallet_asset_index //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-04, STEPS: `[]`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 128 +//! DATE: 2021-06-16, STEPS: `[]`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("pint-local"), DB CACHE: 128 // Executed Command: // ./target/release/pint @@ -13,14 +13,16 @@ // -p // pallet_asset_index // -e -// add_asset +// * // --execution -// wasm +// Wasm // --wasm-execution -// compiled +// Compiled // --raw // --output // ./runtime/src/weights/pallet_asset_index.rs +// --chain +// pint-local #![allow(unused_parens)] #![allow(unused_imports)] @@ -32,7 +34,12 @@ use sp_std::marker::PhantomData; pub struct WeightInfo(PhantomData); impl pallet_asset_index::WeightInfo for WeightInfo { fn add_asset() -> Weight { - (32_000_000 as Weight) + (38_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + fn set_metadata() -> Weight { + (18_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) }