Skip to content
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

feat: existential deposits in asset registry #146

Merged
merged 7 commits into from
Aug 30, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 21 additions & 4 deletions node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,12 @@ pub fn testnet_parachain_config(para_id: ParaId) -> Result<ChainSpec, String> {
vec![hex!["30035c21ba9eda780130f2029a80c3e962f56588bc04c36be95a225cb536fb55"].into()],
hex!["30035c21ba9eda780130f2029a80c3e962f56588bc04c36be95a225cb536fb55"].into(), // SAME AS ROOT
vec![].into(),
vec![b"hKSM".to_vec(), b"hDOT".to_vec(), b"hETH".to_vec(), b"hUSDT".to_vec()],
vec![
(b"hKSM".to_vec(), 1_000u128),
(b"hDOT".to_vec(), 1_000u128),
(b"hETH".to_vec(), 1_000u128),
(b"hUSDT".to_vec(), 1_000u128),
],
)
},
// Bootnodes
Expand Down Expand Up @@ -293,7 +298,12 @@ pub fn parachain_development_config(para_id: ParaId) -> Result<ChainSpec, String
],
get_account_id_from_seed::<sr25519::Public>("Alice"), // SAME AS ROOT
get_vesting_config_for_test(),
vec![b"hKSM".to_vec(), b"hDOT".to_vec(), b"hETH".to_vec(), b"hUSDT".to_vec()],
vec![
(b"hKSM".to_vec(), 1_000u128),
(b"hDOT".to_vec(), 1_000u128),
(b"hETH".to_vec(), 1_000u128),
(b"hUSDT".to_vec(), 1_000u128),
],
)
},
// Bootnodes
Expand Down Expand Up @@ -437,7 +447,12 @@ pub fn local_parachain_config(para_id: ParaId) -> Result<ChainSpec, String> {
],
get_account_id_from_seed::<sr25519::Public>("Alice"), // SAME AS ROOT
get_vesting_config_for_test(),
vec![b"hKSM".to_vec(), b"hDOT".to_vec(), b"hETH".to_vec(), b"hUSDT".to_vec()],
vec![
(b"hKSM".to_vec(), 1_000u128),
(b"hDOT".to_vec(), 1_000u128),
(b"hETH".to_vec(), 1_000u128),
(b"hUSDT".to_vec(), 1_000u128),
],
)
},
// Bootnodes
Expand Down Expand Up @@ -516,6 +531,7 @@ fn parachain_genesis(
asset_registry: AssetRegistryConfig {
asset_names: vec![],
native_asset_name: TOKEN_SYMBOL.as_bytes().to_vec(),
native_existential_deposit: 1_000_000u128,
jak-pan marked this conversation as resolved.
Show resolved Hide resolved
},
multi_transaction_payment: MultiTransactionPaymentConfig {
currencies: vec![],
Expand Down Expand Up @@ -572,7 +588,7 @@ fn testnet_parachain_genesis(
tech_committee_members: Vec<AccountId>,
tx_fee_payment_account: AccountId,
vesting_list: Vec<(AccountId, BlockNumber, BlockNumber, u32, Balance)>,
registered_assets: Vec<Vec<u8>>,
registered_assets: Vec<(Vec<u8>, Balance)>, // (Asset name, Existential deposit)
) -> GenesisConfig {
GenesisConfig {
system: SystemConfig {
Expand Down Expand Up @@ -617,6 +633,7 @@ fn testnet_parachain_genesis(
asset_registry: AssetRegistryConfig {
asset_names: registered_assets,
native_asset_name: TOKEN_SYMBOL.as_bytes().to_vec(),
native_existential_deposit: 1_000_000u128,
},
multi_transaction_payment: MultiTransactionPaymentConfig {
currencies: vec![],
Expand Down
3 changes: 3 additions & 0 deletions pallets/asset-registry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ serde = { features = ["derive"], optional = true, version = "1.0.101" }
# Local dependencies
primitives = { path = "../../primitives", default-features = false }

# ORML dependencies
orml-traits = { git = "/~https://github.com/open-web3-stack/open-runtime-module-library", rev = "8d5432c3458702a7df14b374bddde43a2a20aa43", default-features = false }

# Substrate dependencies
frame-support = { git = "/~https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9", default-features = false }
frame-system = { git = "/~https://github.com/paritytech/substrate", branch = "polkadot-v0.9.9", default-features = false }
Expand Down
18 changes: 13 additions & 5 deletions pallets/asset-registry/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,31 @@ use sp_std::vec;
benchmarks! {
register{
let name = vec![1; T::StringLimit::get() as usize];
let ed = T::Balance::from(1_000_000u32);

// This makes sure that next asset id is equal to native asset id
// In such case, one additional operation is performed to skip the id (aka worst case)
assert_eq!(crate::Pallet::<T>::next_asset_id(), T::AssetId::from(0u8));

}: _(RawOrigin::Root, name.clone(), AssetType::Token)
}: _(RawOrigin::Root, name.clone(), AssetType::Token, ed)
verify {
let bname = crate::Pallet::<T>::to_bounded_name(name).unwrap();
assert_eq!(crate::Pallet::<T>::asset_ids(bname), Some(T::AssetId::from(1u8)));
}

update{
let name = b"NAME".to_vec();
let ed = T::Balance::from(1_000_000u32);
assert_eq!(crate::Pallet::<T>::next_asset_id(), T::AssetId::from(0u8));
let _ = crate::Pallet::<T>::register(RawOrigin::Root.into(), name.clone(), AssetType::Token);
let _ = crate::Pallet::<T>::register(RawOrigin::Root.into(), name.clone(), AssetType::Token, ed);

let new_name= vec![1; T::StringLimit::get() as usize];

let asset_id = T::AssetId::from(1u8);

}: _(RawOrigin::Root, asset_id, new_name.clone(), AssetType::PoolShare(T::AssetId::from(10u8),T::AssetId::from(20u8)))
let new_ed = T::Balance::from(2_000_000u32);

}: _(RawOrigin::Root, asset_id, new_name.clone(), AssetType::PoolShare(T::AssetId::from(10u8),T::AssetId::from(20u8)), Some(new_ed))
verify {
let bname = crate::Pallet::<T>::to_bounded_name(new_name).unwrap();
assert_eq!(crate::Pallet::<T>::asset_ids(&bname), Some(T::AssetId::from(1u8)));
Expand All @@ -60,17 +64,20 @@ benchmarks! {
let expected = AssetDetails{
asset_type: AssetType::PoolShare(T::AssetId::from(10u8), T::AssetId::from(20u8)),
locked: false,
existential_deposit: new_ed,
name: bname.clone(),};

assert_eq!(stored.asset_type, expected.asset_type);
assert_eq!(stored.locked, expected.locked);
assert_eq!(stored.existential_deposit, expected.existential_deposit);
assert_eq!(stored.name.to_vec(), expected.name.to_vec());
}

set_metadata{
let name = b"NAME".to_vec();
let ed = T::Balance::from(1_000_000u32);
assert_eq!(crate::Pallet::<T>::next_asset_id(), T::AssetId::from(0u8));
let _ = crate::Pallet::<T>::register(RawOrigin::Root.into(), name.clone(), AssetType::Token);
let _ = crate::Pallet::<T>::register(RawOrigin::Root.into(), name.clone(), AssetType::Token, ed);

let asset_id = T::AssetId::from(1u8);

Expand Down Expand Up @@ -99,8 +106,9 @@ benchmarks! {

set_location{
let name = b"NAME".to_vec();
let ed = T::Balance::from(1_000_000u32);
assert_eq!(crate::Pallet::<T>::next_asset_id(), T::AssetId::from(0u8));
let _ = crate::Pallet::<T>::register(RawOrigin::Root.into(), name.clone(), AssetType::Token);
let _ = crate::Pallet::<T>::register(RawOrigin::Root.into(), name.clone(), AssetType::Token, ed);

let asset_id = T::AssetId::from(1u8);

Expand Down
101 changes: 64 additions & 37 deletions pallets/asset-registry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ use primitives::traits::{Registry, ShareTokenRegistry};
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::sp_runtime::traits::AtLeast32BitUnsigned;

#[pallet::config]
pub trait Config: frame_system::Config {
Expand All @@ -61,6 +62,9 @@ pub mod pallet {
/// Asset type
type AssetId: Parameter + Member + Default + Copy + BaseArithmetic + MaybeSerializeDeserialize + MaxEncodedLen;

/// Balance type
type Balance: Parameter + Member + AtLeast32BitUnsigned + Default + Copy + MaybeSerializeDeserialize;

/// Asset location type
type AssetNativeLocation: Parameter + Member + Default;

Expand Down Expand Up @@ -109,7 +113,7 @@ pub mod pallet {
_,
Twox64Concat,
T::AssetId,
AssetDetails<T::AssetId, BoundedVec<u8, T::StringLimit>>,
AssetDetails<T::AssetId, T::Balance, BoundedVec<u8, T::StringLimit>>,
OptionQuery,
>;

Expand All @@ -121,7 +125,8 @@ pub mod pallet {
#[pallet::storage]
#[pallet::getter(fn asset_ids)]
/// Mapping between asset name and asset id.
pub type AssetIds<T: Config> = StorageMap<_, Blake2_128Concat, BoundedVec<u8, T::StringLimit>, T::AssetId, OptionQuery>;
pub type AssetIds<T: Config> =
StorageMap<_, Blake2_128Concat, BoundedVec<u8, T::StringLimit>, T::AssetId, OptionQuery>;

#[pallet::storage]
#[pallet::getter(fn locations)]
Expand All @@ -131,7 +136,8 @@ pub mod pallet {
#[pallet::storage]
#[pallet::getter(fn location_assets)]
/// Local asset for native location.
pub type LocationAssets<T: Config> = StorageMap<_, Blake2_128Concat, T::AssetNativeLocation, T::AssetId, OptionQuery>;
pub type LocationAssets<T: Config> =
StorageMap<_, Blake2_128Concat, T::AssetNativeLocation, T::AssetId, OptionQuery>;

#[pallet::storage]
#[pallet::getter(fn asset_metadata)]
Expand All @@ -140,39 +146,24 @@ pub mod pallet {
StorageMap<_, Twox64Concat, T::AssetId, AssetMetadata<BoundedVec<u8, T::StringLimit>>, OptionQuery>;

#[pallet::genesis_config]
pub struct GenesisConfig {
pub asset_names: Vec<Vec<u8>>,
pub struct GenesisConfig<T: Config> {
pub asset_names: Vec<(Vec<u8>, T::Balance)>,
pub native_asset_name: Vec<u8>,
pub native_existential_deposit: T::Balance,
}

#[cfg(feature = "std")]
impl Default for GenesisConfig {
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
GenesisConfig {
GenesisConfig::<T> {
asset_names: vec![],
native_asset_name: b"BSX".to_vec(),
native_existential_deposit: Default::default(),
}
}
}
#[cfg(feature = "std")]
impl GenesisConfig {
/// Direct implementation of `GenesisBuild::build_storage`.
///
/// Kept in order not to break dependency.
pub fn build_storage<T: Config>(&self) -> Result<sp_runtime::Storage, String> {
<Self as GenesisBuild<T>>::build_storage(self)
}

/// Direct implementation of `GenesisBuild::assimilate_storage`.
///
/// Kept in order not to break dependency.
pub fn assimilate_storage<T: Config>(&self, storage: &mut sp_runtime::Storage) -> Result<(), String> {
<Self as GenesisBuild<T>>::assimilate_storage(self, storage)
}
}

#[pallet::genesis_build]
impl<T: Config> GenesisBuild<T> for GenesisConfig {
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
fn build(&self) {
// Register native asset first
// It is to make sure that native is registered as any other asset
Expand All @@ -184,16 +175,17 @@ pub mod pallet {
let details = AssetDetails {
name: native_asset_name,
asset_type: AssetType::Token,
existential_deposit: self.native_existential_deposit,
locked: false,
};

Assets::<T>::insert(T::NativeAssetId::get(), details);

self.asset_names.iter().for_each(|name| {
self.asset_names.iter().for_each(|(name, ed)| {
let bounded_name = Pallet::<T>::to_bounded_name(name.to_vec())
.map_err(|_| panic!("Invalid asset name!"))
.unwrap();
let _ = Pallet::<T>::register_asset(bounded_name, AssetType::Token)
let _ = Pallet::<T>::register_asset(bounded_name, AssetType::Token, *ed)
.map_err(|_| panic!("Failed to register asset"));
})
}
Expand Down Expand Up @@ -229,7 +221,12 @@ pub mod pallet {
/// Emits 'Registered` event when successful.
#[pallet::weight(<T as Config>::WeightInfo::register())]
#[transactional]
pub fn register(origin: OriginFor<T>, name: Vec<u8>, asset_type: AssetType<T::AssetId>) -> DispatchResult {
pub fn register(
origin: OriginFor<T>,
name: Vec<u8>,
asset_type: AssetType<T::AssetId>,
existential_deposit: T::Balance,
) -> DispatchResult {
T::RegistryOrigin::ensure_origin(origin)?;

let bounded_name = Self::to_bounded_name(name)?;
Expand All @@ -239,7 +236,7 @@ pub mod pallet {
Error::<T>::AssetAlreadyRegistered
);

Self::register_asset(bounded_name, asset_type)?;
Self::register_asset(bounded_name, asset_type, existential_deposit)?;

Ok(())
}
Expand All @@ -258,6 +255,7 @@ pub mod pallet {
asset_id: T::AssetId,
name: Vec<u8>,
asset_type: AssetType<T::AssetId>,
existential_deposit: Option<T::Balance>,
) -> DispatchResult {
T::RegistryOrigin::ensure_origin(origin)?;

Expand All @@ -280,6 +278,7 @@ pub mod pallet {

detail.name = bounded_name.clone();
detail.asset_type = asset_type;
detail.existential_deposit = existential_deposit.unwrap_or(detail.existential_deposit);

Self::deposit_event(Event::Updated(asset_id, bounded_name, asset_type));

Expand Down Expand Up @@ -360,6 +359,7 @@ impl<T: Config> Pallet<T> {
fn register_asset(
name: BoundedVec<u8, T::StringLimit>,
asset_type: AssetType<T::AssetId>,
existential_deposit: T::Balance,
) -> Result<T::AssetId, DispatchError> {
NextAssetId::<T>::mutate(|value| -> Result<T::AssetId, DispatchError> {
// Check if current id does not clash with CORE ASSET ID.
Expand All @@ -379,6 +379,7 @@ impl<T: Config> Pallet<T> {
let details = AssetDetails {
name: name.clone(),
asset_type,
existential_deposit,
locked: false,
};

Expand All @@ -397,13 +398,17 @@ impl<T: Config> Pallet<T> {
}

/// Create asset for given name or return existing AssetId if such asset already exists.
pub fn get_or_create_asset(name: Vec<u8>, asset_type: AssetType<T::AssetId>) -> Result<T::AssetId, DispatchError> {
pub fn get_or_create_asset(
name: Vec<u8>,
asset_type: AssetType<T::AssetId>,
existential_deposit: T::Balance,
) -> Result<T::AssetId, DispatchError> {
let bounded_name: BoundedVec<u8, T::StringLimit> = Self::to_bounded_name(name)?;

if let Some(asset_id) = AssetIds::<T>::get(&bounded_name) {
Ok(asset_id)
} else {
Self::register_asset(bounded_name, asset_type)
Self::register_asset(bounded_name, asset_type, existential_deposit)
}
}

Expand All @@ -418,7 +423,7 @@ impl<T: Config> Pallet<T> {
}
}

impl<T: Config> Registry<T::AssetId, Vec<u8>, DispatchError> for Pallet<T> {
impl<T: Config> Registry<T::AssetId, Vec<u8>, T::Balance, DispatchError> for Pallet<T> {
fn exists(asset_id: T::AssetId) -> bool {
Assets::<T>::contains_key(&asset_id)
}
Expand All @@ -432,18 +437,40 @@ impl<T: Config> Registry<T::AssetId, Vec<u8>, DispatchError> for Pallet<T> {
}
}

fn create_asset(name: &Vec<u8>) -> Result<T::AssetId, DispatchError> {
Self::get_or_create_asset(name.clone(), AssetType::Token)
fn create_asset(name: &Vec<u8>, existential_deposit: T::Balance) -> Result<T::AssetId, DispatchError> {
Self::get_or_create_asset(name.clone(), AssetType::Token, existential_deposit)
}
}

impl<T: Config> ShareTokenRegistry<T::AssetId, Vec<u8>, DispatchError> for Pallet<T> {
impl<T: Config> ShareTokenRegistry<T::AssetId, Vec<u8>, T::Balance, DispatchError> for Pallet<T> {
fn retrieve_shared_asset(name: &Vec<u8>, _assets: &Vec<T::AssetId>) -> Result<T::AssetId, DispatchError> {
Self::retrieve_asset(name)
}

fn create_shared_asset(name: &Vec<u8>, assets: &Vec<T::AssetId>) -> Result<T::AssetId, DispatchError> {
fn create_shared_asset(
name: &Vec<u8>,
assets: &Vec<T::AssetId>,
existential_deposit: T::Balance,
) -> Result<T::AssetId, DispatchError> {
ensure!(assets.len() == 2, Error::<T>::InvalidSharedAssetLen);
Self::get_or_create_asset(name.clone(), AssetType::PoolShare(assets[0], assets[1]))
Self::get_or_create_asset(
name.clone(),
AssetType::PoolShare(assets[0], assets[1]),
existential_deposit,
)
}
}

use orml_traits::GetByKey;

// Return Existential deposit of an asset
impl<T: Config> GetByKey<T::AssetId, T::Balance> for Pallet<T> {
fn get(k: &T::AssetId) -> T::Balance {
if let Some(details) = Self::assets(k) {
details.existential_deposit
} else {
// Asset does not exists, so it does not really matter.
Default::default()
}
}
}
Loading