Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Pallet Assets: Create new asset classes from genesis config (#9742)
Browse files Browse the repository at this point in the history
* Pallet Assets: Allow creating asset classes from genesis config

* Add accounts and metadata to genesis config

* whitespace fixes

* Update more chainspecs

* Run rustfmt over code

* More formatting fixes

* Update frame/assets/src/lib.rs

Improve error message

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* Update frame/assets/src/lib.rs

Improve error message

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
  • Loading branch information
vgeddes and shawntabrizi authored Sep 30, 2021
1 parent 8b95e23 commit 3302199
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 6 deletions.
1 change: 1 addition & 0 deletions bin/node/cli/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ pub fn testnet_genesis(
max_members: 999,
},
vesting: Default::default(),
assets: Default::default(),
gilt: Default::default(),
transaction_storage: Default::default(),
}
Expand Down
2 changes: 1 addition & 1 deletion bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1280,7 +1280,7 @@ construct_runtime!(
Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>},
Bounties: pallet_bounties::{Pallet, Call, Storage, Event<T>},
Tips: pallet_tips::{Pallet, Call, Storage, Event<T>},
Assets: pallet_assets::{Pallet, Call, Storage, Event<T>},
Assets: pallet_assets::{Pallet, Call, Storage, Event<T>, Config<T>},
Mmr: pallet_mmr::{Pallet, Storage},
Lottery: pallet_lottery::{Pallet, Call, Storage, Event<T>},
Gilt: pallet_gilt::{Pallet, Call, Storage, Event<T>, Config},
Expand Down
1 change: 1 addition & 0 deletions bin/node/testing/src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ pub fn config_endowed(
treasury: Default::default(),
society: SocietyConfig { members: vec![alice(), bob()], pot: 0, max_members: 999 },
vesting: Default::default(),
assets: Default::default(),
gilt: Default::default(),
transaction_storage: Default::default(),
}
Expand Down
102 changes: 100 additions & 2 deletions frame/assets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ use sp_runtime::{
};
use sp_std::{borrow::Borrow, convert::TryInto, prelude::*};

#[cfg(feature = "std")]
use frame_support::traits::GenesisBuild;

pub use pallet::*;
pub use weights::WeightInfo;

Expand All @@ -180,10 +183,22 @@ pub mod pallet {
type Event: From<Event<Self, I>> + IsType<<Self as frame_system::Config>::Event>;

/// The units in which we record balances.
type Balance: Member + Parameter + AtLeast32BitUnsigned + Default + Copy + MaxEncodedLen;
type Balance: Member
+ Parameter
+ AtLeast32BitUnsigned
+ Default
+ Copy
+ MaybeSerializeDeserialize
+ MaxEncodedLen;

/// Identifier for the class of asset.
type AssetId: Member + Parameter + Default + Copy + HasCompact + MaxEncodedLen;
type AssetId: Member
+ Parameter
+ Default
+ Copy
+ HasCompact
+ MaybeSerializeDeserialize
+ MaxEncodedLen;

/// The currency mechanism.
type Currency: ReservableCurrency<Self::AccountId>;
Expand Down Expand Up @@ -276,6 +291,89 @@ pub mod pallet {
ConstU32<300_000>,
>;

#[pallet::genesis_config]
pub struct GenesisConfig<T: Config<I>, I: 'static = ()> {
/// Genesis assets: id, owner, is_sufficient, min_balance
pub assets: Vec<(T::AssetId, T::AccountId, bool, T::Balance)>,
/// Genesis metadata: id, name, symbol, decimals
pub metadata: Vec<(T::AssetId, Vec<u8>, Vec<u8>, u8)>,
/// Genesis accounts: id, account_id, balance
pub accounts: Vec<(T::AssetId, T::AccountId, T::Balance)>,
}

#[cfg(feature = "std")]
impl<T: Config<I>, I: 'static> Default for GenesisConfig<T, I> {
fn default() -> Self {
Self {
assets: Default::default(),
metadata: Default::default(),
accounts: Default::default(),
}
}
}

#[pallet::genesis_build]
impl<T: Config<I>, I: 'static> GenesisBuild<T, I> for GenesisConfig<T, I> {
fn build(&self) {
for (id, owner, is_sufficient, min_balance) in &self.assets {
assert!(!Asset::<T, I>::contains_key(id), "Asset id already in use");
assert!(!min_balance.is_zero(), "Min balance should not be zero");
Asset::<T, I>::insert(
id,
AssetDetails {
owner: owner.clone(),
issuer: owner.clone(),
admin: owner.clone(),
freezer: owner.clone(),
supply: Zero::zero(),
deposit: Zero::zero(),
min_balance: *min_balance,
is_sufficient: *is_sufficient,
accounts: 0,
sufficients: 0,
approvals: 0,
is_frozen: false,
},
);
}

for (id, name, symbol, decimals) in &self.metadata {
assert!(Asset::<T, I>::contains_key(id), "Asset does not exist");

let bounded_name: BoundedVec<u8, T::StringLimit> =
name.clone().try_into().expect("asset name is too long");
let bounded_symbol: BoundedVec<u8, T::StringLimit> =
symbol.clone().try_into().expect("asset symbol is too long");

let metadata = AssetMetadata {
deposit: Zero::zero(),
name: bounded_name,
symbol: bounded_symbol,
decimals: *decimals,
is_frozen: false,
};
Metadata::<T, I>::insert(id, metadata);
}

for (id, account_id, amount) in &self.accounts {
let result = <Pallet<T, I>>::increase_balance(
*id,
account_id,
*amount,
|details| -> DispatchResult {
debug_assert!(
T::Balance::max_value() - details.supply >= *amount,
"checked in prep; qed"
);
details.supply = details.supply.saturating_add(*amount);
Ok(())
},
);
assert!(result.is_ok());
}
}
}

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config<I>, I: 'static = ()> {
Expand Down
23 changes: 20 additions & 3 deletions frame/assets/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,26 @@ pub(crate) fn hooks() -> Vec<Hook> {
}

pub(crate) fn new_test_ext() -> sp_io::TestExternalities {
let t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();

let mut ext = sp_io::TestExternalities::new(t);
let mut storage = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();

let config: pallet_assets::GenesisConfig<Test> = pallet_assets::GenesisConfig {
assets: vec![
// id, owner, is_sufficient, min_balance
(999, 0, true, 1),
],
metadata: vec![
// id, name, symbol, decimals
(999, "Token Name".into(), "TOKEN".into(), 10),
],
accounts: vec![
// id, account_id, balance
(999, 1, 100),
],
};

config.assimilate_storage(&mut storage).unwrap();

let mut ext: sp_io::TestExternalities = storage.into();
ext.execute_with(|| System::set_block_number(1));
ext
}
10 changes: 10 additions & 0 deletions frame/assets/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -784,3 +784,13 @@ fn balance_conversion_should_work() {
);
});
}

#[test]
fn assets_from_genesis_should_exist() {
new_test_ext().execute_with(|| {
assert!(Asset::<Test>::contains_key(999));
assert!(Metadata::<Test>::contains_key(999));
assert_eq!(Assets::balance(999, 1), 100);
assert_eq!(Assets::total_supply(999), 100);
});
}

0 comments on commit 3302199

Please sign in to comment.