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

Improve asset manager #472

Merged
merged 16 commits into from Apr 9, 2022
9 changes: 5 additions & 4 deletions Cargo.lock

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

5 changes: 4 additions & 1 deletion node/src/chain_specs/dolphin.rs
Expand Up @@ -17,7 +17,9 @@
use super::*;
use crate::command::DOLPHIN_PARACHAIN_ID;

use dolphin_runtime::{CouncilConfig, DemocracyConfig, GenesisConfig, TechnicalCommitteeConfig};
use dolphin_runtime::{
AssetManagerConfig, CouncilConfig, DemocracyConfig, GenesisConfig, TechnicalCommitteeConfig,
};
use manta_primitives::helpers::{get_account_id_from_seed, get_collator_keys_from_seed};

/// Specialized `ChainSpec` for the normal parachain runtime.
Expand Down Expand Up @@ -203,6 +205,7 @@ fn dolphin_dev_genesis(
members: endowed_accounts.iter().take(1).cloned().collect(),
phantom: Default::default(),
},
asset_manager: Default::default(),
council_membership: Default::default(),
technical_membership: Default::default(),
aura_ext: Default::default(),
Expand Down
134 changes: 115 additions & 19 deletions pallets/asset-manager/src/lib.rs
Expand Up @@ -41,9 +41,10 @@ pub mod pallet {
use frame_system::pallet_prelude::*;
use manta_primitives::{
assets::{
AssetConfig, AssetIdLocationGetter, AssetMetadata, AssetRegistrar, UnitsToWeightRatio,
AssetConfig, AssetIdLocationGetter, AssetMetadata, AssetRegistrar, FungibleLedger,
UnitsToWeightRatio,
},
types::AssetId,
types::{AssetId, Balance},
};
use sp_runtime::{traits::AccountIdConversion, ArithmeticError};

Expand All @@ -53,16 +54,18 @@ pub mod pallet {
pub struct Pallet<T>(_);

/// Convert AssetId and AssetLocation
impl<T: Config> AssetIdLocationGetter<<T::AssetConfig as AssetConfig>::AssetLocation>
impl<T: Config> AssetIdLocationGetter<<T::AssetConfig as AssetConfig<T>>::AssetLocation>
for Pallet<T>
{
fn get_asset_id(loc: &<T::AssetConfig as AssetConfig>::AssetLocation) -> Option<AssetId> {
fn get_asset_id(
loc: &<T::AssetConfig as AssetConfig<T>>::AssetLocation,
) -> Option<AssetId> {
LocationAssetId::<T>::get(loc)
}

fn get_asset_location(
id: AssetId,
) -> Option<<T::AssetConfig as AssetConfig>::AssetLocation> {
) -> Option<<T::AssetConfig as AssetConfig<T>>::AssetLocation> {
AssetIdLocation::<T>::get(id)
}
}
Expand All @@ -80,7 +83,7 @@ pub mod pallet {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;

/// Asset configuration, e.g. AssetId, Balance, Metadata
type AssetConfig: AssetConfig;
type AssetConfig: AssetConfig<Self>;

/// The origin which may forcibly create or destroy an asset or otherwise alter privileged
/// attributes.
Expand All @@ -90,30 +93,65 @@ pub mod pallet {
type PalletId: Get<PalletId>;
}

#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
pub start_id: AssetId,
pub _marker: PhantomData<T>,
}

#[cfg(feature = "std")]
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
Self {
start_id: 8u32,
stechu marked this conversation as resolved.
Show resolved Hide resolved
_marker: PhantomData::<T>::default(),
stechu marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

#[pallet::genesis_build]
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
fn build(&self) {
NextAssetId::<T>::set(self.start_id);
let asset_id = <T::AssetConfig as AssetConfig<T>>::NativeAssetId::get();
let metadata = <T::AssetConfig as AssetConfig<T>>::NativeAssetMetadata::get();
let location = <T::AssetConfig as AssetConfig<T>>::NativeAssetLocation::get();
AssetIdLocation::<T>::insert(&asset_id, &location);
AssetIdMetadata::<T>::insert(&asset_id, &metadata);
LocationAssetId::<T>::insert(&location, &asset_id);
}
}

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// A new asset registered.
AssetRegistered {
asset_id: AssetId,
asset_address: <T::AssetConfig as AssetConfig>::AssetLocation,
metadata: <T::AssetConfig as AssetConfig>::AssetRegistrarMetadata,
asset_address: <T::AssetConfig as AssetConfig<T>>::AssetLocation,
metadata: <T::AssetConfig as AssetConfig<T>>::AssetRegistrarMetadata,
},
/// An asset's location has been updated.
AssetLocationUpdated {
asset_id: AssetId,
location: <T::AssetConfig as AssetConfig>::AssetLocation,
location: <T::AssetConfig as AssetConfig<T>>::AssetLocation,
},
/// An asset;s metadata has been updated.
AssetMetadataUpdated {
asset_id: AssetId,
metadata: <T::AssetConfig as AssetConfig>::AssetRegistrarMetadata,
metadata: <T::AssetConfig as AssetConfig<T>>::AssetRegistrarMetadata,
},
/// Update units per second of an asset
UnitsPerSecondUpdated {
asset_id: AssetId,
units_per_second: u128,
},
/// Asset minted.
AssetMinted {
asset_id: AssetId,
beneficiary: T::AccountId,
amount: Balance,
},
}

/// Error.
Expand All @@ -123,25 +161,27 @@ pub mod pallet {
LocationAlreadyExists,
/// Error creating asset, e.g. error returned from the implementation layer.
ErrorCreatingAsset,
/// Update a non-exist asset
/// Update a non-exist asset.
UpdateNonExistAsset,
/// Asset already registered.
AssetAlreadyRegistered,
/// Error on ming asset.
stechu marked this conversation as resolved.
Show resolved Hide resolved
MintError,
}

/// AssetId to MultiLocation Map.
/// This is mostly useful when sending an asset to a foreign location.
#[pallet::storage]
#[pallet::getter(fn asset_id_location)]
pub(super) type AssetIdLocation<T: Config> =
StorageMap<_, Blake2_128Concat, AssetId, <T::AssetConfig as AssetConfig>::AssetLocation>;
StorageMap<_, Blake2_128Concat, AssetId, <T::AssetConfig as AssetConfig<T>>::AssetLocation>;

/// MultiLocation to AssetId Map.
/// This is mostly useful when receiving an asset from a foreign location.
#[pallet::storage]
#[pallet::getter(fn location_asset_id)]
pub(super) type LocationAssetId<T: Config> =
StorageMap<_, Blake2_128Concat, <T::AssetConfig as AssetConfig>::AssetLocation, AssetId>;
StorageMap<_, Blake2_128Concat, <T::AssetConfig as AssetConfig<T>>::AssetLocation, AssetId>;

/// AssetId to AssetRegistrar Map.
#[pallet::storage]
Expand All @@ -150,7 +190,7 @@ pub mod pallet {
_,
Blake2_128Concat,
AssetId,
<T::AssetConfig as AssetConfig>::AssetRegistrarMetadata,
<T::AssetConfig as AssetConfig<T>>::AssetRegistrarMetadata,
>;

/// Get the next available AssetId.
Expand Down Expand Up @@ -180,16 +220,16 @@ pub mod pallet {
#[transactional]
pub fn register_asset(
origin: OriginFor<T>,
location: <T::AssetConfig as AssetConfig>::AssetLocation,
metadata: <T::AssetConfig as AssetConfig>::AssetRegistrarMetadata,
location: <T::AssetConfig as AssetConfig<T>>::AssetLocation,
metadata: <T::AssetConfig as AssetConfig<T>>::AssetRegistrarMetadata,
) -> DispatchResult {
T::ModifierOrigin::ensure_origin(origin)?;
ensure!(
!LocationAssetId::<T>::contains_key(&location),
Error::<T>::LocationAlreadyExists
);
let asset_id = Self::get_next_asset_id()?;
<T::AssetConfig as AssetConfig>::AssetRegistrar::create_asset(
<T::AssetConfig as AssetConfig<T>>::AssetRegistrar::create_asset(
asset_id,
metadata.min_balance(),
metadata.clone().into(),
Expand Down Expand Up @@ -220,7 +260,7 @@ pub mod pallet {
pub fn update_asset_location(
origin: OriginFor<T>,
#[pallet::compact] asset_id: AssetId,
location: <T::AssetConfig as AssetConfig>::AssetLocation,
location: <T::AssetConfig as AssetConfig<T>>::AssetLocation,
) -> DispatchResult {
// checks validity
T::ModifierOrigin::ensure_origin(origin)?;
Expand Down Expand Up @@ -253,7 +293,7 @@ pub mod pallet {
pub fn update_asset_metadata(
origin: OriginFor<T>,
#[pallet::compact] asset_id: AssetId,
metadata: <T::AssetConfig as AssetConfig>::AssetRegistrarMetadata,
metadata: <T::AssetConfig as AssetConfig<T>>::AssetRegistrarMetadata,
) -> DispatchResult {
T::ModifierOrigin::ensure_origin(origin)?;
ensure!(
Expand Down Expand Up @@ -292,6 +332,45 @@ pub mod pallet {
});
Ok(())
}

/// Mint asset by its asset id to a beneficiary.
///
/// * `origin`: Caller of this extrinsic, the acess control is specfied by `ForceOrigin`.
stechu marked this conversation as resolved.
Show resolved Hide resolved
/// * `asset_id`: AssetId to be updated.
/// * `beneficiary`: Account to mint the asset.
/// * `amount`: Amount of asset being minted.
/// # <weight>
/// TODO: get actual weight
/// # </weight>
#[pallet::weight(50_000_000)]
stechu marked this conversation as resolved.
Show resolved Hide resolved
#[transactional]
pub fn mint_asset(
stechu marked this conversation as resolved.
Show resolved Hide resolved
origin: OriginFor<T>,
#[pallet::compact] asset_id: AssetId,
beneficiary: T::AccountId,
amount: Balance,
) -> DispatchResult {
T::ModifierOrigin::ensure_origin(origin)?;
ensure!(
AssetIdLocation::<T>::contains_key(&asset_id),
Error::<T>::UpdateNonExistAsset
);
ensure!(
<T::AssetConfig as AssetConfig<T>>::FungibleLedger::mint(
asset_id,
&beneficiary,
amount
)
.is_ok(),
Error::<T>::MintError
);
Self::deposit_event(Event::<T>::AssetMinted {
asset_id,
beneficiary,
amount,
});
Ok(())
}
}

impl<T: Config> Pallet<T> {
Expand All @@ -309,4 +388,21 @@ pub mod pallet {
T::PalletId::get().into_account()
}
}

#[cfg(feature = "std")]
impl<T: Config> GenesisConfig<T> {
/// Direct implementation of `GenesisBuild::build_storage`.
///
/// Kept in order not to break dependency.
pub fn build_storage(&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(&self, storage: &mut sp_runtime::Storage) -> Result<(), String> {
<Self as GenesisBuild<T>>::assimilate_storage(self, storage)
}
}
}