Create a storage structure (struct)
Please read Substrate to Polkadot SDK page first.
Creating a struct of similarly grouped storage items is an orderly way to keep track of them.
When grouped in this way, it is easier to reference them than it is if individual StorageValue
items are kept separately.
This can make testing and genesis configuration easier.
This guide shows you how to create a StorageValue
storage item that holds a struct and is used in on_initialize
.
This struct does the following:
- Keeps track of an initial amount (
issuance
) - Keeps track of the account that receives that amount (
minter
) - Keeps track of an account that can burn some amount (
burner
) - Is (partially) used in
on_initialize
Before you begin
Make sure you have a working pallet to build your struct for. Use the template pallet if you don't have one you're already working on.
-
Create a struct
Name the struct
MetaData
and declare its different types:#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)] pub struct MetaData<AccountId, Balance> { issuance: Balance, minter: AccountId, burner: AccountId, }
-
Declare the struct as a storage item
Use
StorageValue
to declare the struct as a new single item in storage:#[pallet::storage] #[pallet::getter(fn meta_data)] pub(super) type MetaDataStore<T: Config> = StorageValue<_, MetaData<T::AccountId, T::Balance>, ValueQuery>;
-
Configure
GenesisConfig
Use the
#[pallet::genesis_config]
attribute to initialize values from yourMetaData
struct.// Declare `admin` as type `T::AccountId`. #[pallet::genesis_config] pub struct GenesisConfig<T: Config> { pub admin: T::AccountId, } // Give it a default value. #[cfg(feature = "std")] impl<T: Config> Default for GenesisConfig<T> { fn default() -> Self { Self { admin: Default::default(), } } }
This
admin
variable must correspond with the variable used in thenode/chainspec.rs
file insidefn testnet_genesis
. -
Configure
GenesisBuild
Use the
#[pallet::genesis_build]
attribute to initialize the values of your struct, usingadmin
to initialize the values of typeT::AccountId
:#[pallet::genesis_build] impl<T: Config> GenesisBuild<T> for GenesisConfig<T> { fn build(&self) { MetaDataStore::<T>::put(MetaData { issuance: Zero::zero(), minter: self.admin.clone(), burner: self.admin.clone(), }); } }
-
Use the struct in
on_initialize()
Assign an amount to the
issuance
field ofMetaData
to be initialized when the chain is launched:fn on_initialize(_n: T::BlockNumber) -> Weight { // Create an alias for the StorageValue struct. let mut meta = MetaDataStore::<T>::get(); // Add a value to the `issuance` field. let value: T::Balance = 50u8.into(); meta.issuance = meta.issuance.saturating_add(value); // Add the amount to the `minter` account in storage. Accounts::<T>::mutate(&meta.minter, |bal| { *bal = bal.saturating_add(value); }); }
The on_initialize
function ensures that the values for the specified items are written to storage when the chain is launched.
Examples
reward-coin
example pallet