#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod weights;
pub use pallet::*;
use weights::*;
#[frame_support::pallet]
pub mod pallet {
use super::*;
use codec::alloc::collections::BTreeSet;
use frame_support::{dispatch::DispatchResult, pallet_prelude::*};
use frame_system::pallet_prelude::*;
#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type WeightInfo: WeightInfo;
type MaxSize: Get<u32>;
}
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
#[pallet::type_value]
pub fn DefaultCurrent<T: Config>() -> u32 {
0
}
#[pallet::storage]
#[pallet::getter(fn identity_number)]
pub type IdentityNumber<T: Config> =
StorageValue<Value = u32, QueryKind = ValueQuery, OnEmpty = DefaultCurrent<T>>;
#[pallet::storage]
#[pallet::getter(fn revoked_identity_number)]
pub type RevokedIdentityNumber<T: Config> =
StorageValue<Value = u32, QueryKind = ValueQuery, OnEmpty = DefaultCurrent<T>>;
#[pallet::storage]
#[pallet::getter(fn get_signal_count)]
pub type SignalCount<T: Config> =
StorageValue<Value = u32, QueryKind = ValueQuery, OnEmpty = DefaultCurrent<T>>;
#[pallet::storage]
#[pallet::unbounded]
#[pallet::getter(fn identity_list)]
pub type IdentityList<T: Config> =
StorageMap<_, Blake2_128Concat, T::AccountId, BTreeSet<u32>, ValueQuery>;
#[pallet::storage]
#[pallet::unbounded]
#[pallet::getter(fn identity_trait_list)]
pub type IdentityTraitList<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat,
u32,
Blake2_128Concat,
BoundedVec<u8, T::MaxSize>,
BoundedVec<u8, T::MaxSize>,
ValueQuery,
>;
#[pallet::storage]
#[pallet::unbounded]
#[pallet::getter(fn get_signal_record)]
pub type SignatureSignal<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat,
u32,
Blake2_128Concat,
u32,
BoundedVec<u8, T::MaxSize>,
>;
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
IdentityCreated(u32, T::AccountId),
IdentityRevoked(u32, T::AccountId),
IdentityUpdated(u32, T::AccountId),
SignedSignal(u32, T::AccountId, BoundedVec<u8, T::MaxSize>),
}
#[pallet::error]
#[derive(PartialEq, Eq)]
pub enum Error<T> {
NoneValue,
StorageOverflow,
IdentityNotOwned,
}
impl<T: Config> Pallet<T> {
fn is_identity_owned_by_sender(account_id: &T::AccountId, identity_id: &u32) -> bool {
match <IdentityList<T>>::try_get(account_id) {
Result::Ok(ids) => ids.contains(identity_id),
Result::Err(_) => false,
}
}
}
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::weight(T::WeightInfo::create_identity())]
#[pallet::call_index(0)]
pub fn create_identity(origin: OriginFor<T>) -> DispatchResult {
let who = ensure_signed(origin)?;
let current_id: u32 = <IdentityNumber<T>>::get();
<IdentityNumber<T>>::try_mutate(|current_id| -> DispatchResult {
*current_id = current_id.checked_add(1).ok_or(Error::<T>::StorageOverflow)?;
Ok(())
})?;
let new_id: u32 = <IdentityNumber<T>>::get();
<IdentityList<T>>::try_mutate(&who, |ids| -> DispatchResult {
ids.insert(current_id);
Ok(())
})?;
<IdentityNumber<T>>::put(new_id);
Self::deposit_event(Event::IdentityCreated(current_id, who));
Ok(())
}
#[pallet::weight(T::WeightInfo::revoke_identity())]
#[pallet::call_index(1)]
pub fn revoke_identity(origin: OriginFor<T>, identity_id: u32) -> DispatchResult {
let who = ensure_signed(origin)?;
<RevokedIdentityNumber<T>>::try_mutate(|current_id| -> DispatchResult {
*current_id = current_id.checked_add(1).ok_or(Error::<T>::StorageOverflow)?;
Ok(())
})?;
let new_total = <RevokedIdentityNumber<T>>::get();
<IdentityList<T>>::try_mutate(&who, |ids| -> DispatchResult {
ensure!(ids.remove(&identity_id), Error::<T>::IdentityNotOwned);
Ok(())
})?;
<RevokedIdentityNumber<T>>::put(new_total);
Self::deposit_event(Event::IdentityRevoked(identity_id, who));
Ok(())
}
#[pallet::weight(T::WeightInfo::add_or_update_identity_trait())]
#[pallet::call_index(2)]
pub fn add_or_update_identity_trait(
origin: OriginFor<T>,
identity_id: u32,
key: BoundedVec<u8, T::MaxSize>,
value: BoundedVec<u8, T::MaxSize>,
) -> DispatchResult {
let who = ensure_signed(origin)?;
ensure!(
Self::is_identity_owned_by_sender(&who, &identity_id),
Error::<T>::IdentityNotOwned
);
<IdentityTraitList<T>>::try_mutate(identity_id, key, |v| -> DispatchResult {
*v = value;
Ok(())
})?;
Self::deposit_event(Event::IdentityUpdated(identity_id, who));
Ok(())
}
#[pallet::weight(T::WeightInfo::remove_identity_trait())]
#[pallet::call_index(3)]
pub fn remove_identity_trait(
origin: OriginFor<T>,
identity_id: u32,
key: BoundedVec<u8, T::MaxSize>,
) -> DispatchResult {
let who = ensure_signed(origin)?;
ensure!(
Self::is_identity_owned_by_sender(&who, &identity_id),
Error::<T>::IdentityNotOwned
);
<IdentityTraitList<T>>::remove(identity_id, key);
Self::deposit_event(Event::IdentityUpdated(identity_id, who));
Ok(())
}
#[pallet::weight(T::WeightInfo::sign_for_identity())]
#[pallet::call_index(4)]
pub fn sign_for_identity(
origin: OriginFor<T>,
identity_id: u32,
content: BoundedVec<u8, T::MaxSize>,
) -> DispatchResult {
let who = ensure_signed(origin)?;
ensure!(
Self::is_identity_owned_by_sender(&who, &identity_id),
Error::<T>::IdentityNotOwned
);
let signal_id: u32 = <SignalCount<T>>::get();
<SignalCount<T>>::try_mutate(|signal_id| -> DispatchResult {
*signal_id = signal_id.checked_add(1).ok_or(Error::<T>::StorageOverflow)?;
Ok(())
})?;
let new_id: u32 = <SignalCount<T>>::get();
<SignatureSignal<T>>::insert(&identity_id, &signal_id, &content);
<SignalCount<T>>::put(new_id);
Self::deposit_event(Event::SignedSignal(identity_id, who, content));
Ok(())
}
}
}