#![cfg_attr(not(feature = "std"), no_std)]
use frame_support::{pallet_prelude::*, traits::ReservableCurrency};
use frame_system::pallet_prelude::*;
pub use pallet::*;
use scale_info::TypeInfo;
pub use weights::*;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
pub mod weights;
pub type DocumentId = u128;
pub type DocumentVersion = u64;
#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
#[scale_info(skip_type_params(T))]
pub struct Anchor<T: Config> {
account_id: T::AccountId,
document_id: DocumentId,
document_version: DocumentVersion,
hash: T::Hash,
deposit: T::Balance,
}
#[frame_support::pallet]
pub mod pallet {
use super::*;
#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type Balance: frame_support::traits::tokens::Balance;
type Currency: ReservableCurrency<Self::AccountId, Balance = Self::Balance>;
type DefaultAnchorDeposit: Get<Self::Balance>;
type AdminOrigin: EnsureOrigin<Self::RuntimeOrigin>;
type WeightInfo: WeightInfo;
}
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::storage]
#[pallet::getter(fn get_anchor)]
pub type Anchors<T: Config> =
StorageMap<_, Blake2_256, (DocumentId, DocumentVersion), Anchor<T>>;
#[pallet::storage]
#[pallet::getter(fn get_personal_anchor)]
pub type PersonalAnchors<T: Config> = StorageDoubleMap<
_,
Blake2_256,
T::AccountId,
Blake2_256,
(DocumentId, DocumentVersion),
(),
>;
#[pallet::storage]
#[pallet::getter(fn get_anchor_deposit)]
pub type AnchorDeposit<T: Config> =
StorageValue<_, T::Balance, ValueQuery, T::DefaultAnchorDeposit>;
#[pallet::event]
#[pallet::generate_deposit(pub (super) fn deposit_event)]
pub enum Event<T: Config> {
AnchorAdded {
account_id: T::AccountId,
document_id: u128,
document_version: u64,
hash: T::Hash,
deposit: T::Balance,
},
AnchorRemoved {
account_id: T::AccountId,
document_id: u128,
document_version: u64,
hash: T::Hash,
deposit: T::Balance,
},
DepositSet { new_deposit: T::Balance },
}
#[pallet::error]
pub enum Error<T> {
AnchorAlreadyExists,
PersonalAnchorAlreadyExists,
AnchorNotFound,
PersonalAnchorNotFound,
}
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::weight(T::WeightInfo::set_anchor())]
#[pallet::call_index(0)]
pub fn set_anchor(
origin: OriginFor<T>,
document_id: u128,
document_version: u64,
hash: T::Hash,
) -> DispatchResult {
let account_id = ensure_signed(origin)?;
ensure!(
Anchors::<T>::get((document_id, document_version)).is_none(),
Error::<T>::AnchorAlreadyExists
);
ensure!(
PersonalAnchors::<T>::get(account_id.clone(), (document_id, document_version))
.is_none(),
Error::<T>::PersonalAnchorAlreadyExists
);
let deposit = AnchorDeposit::<T>::get();
T::Currency::reserve(&account_id, deposit)?;
let anchor = Anchor::<T> {
account_id: account_id.clone(),
document_id,
document_version,
hash,
deposit,
};
Anchors::<T>::insert((document_id, document_version), anchor);
PersonalAnchors::<T>::insert(account_id.clone(), (document_id, document_version), ());
Self::deposit_event(Event::AnchorAdded {
account_id,
document_id,
document_version,
hash,
deposit,
});
Ok(())
}
#[pallet::weight(T::WeightInfo::remove_anchor())]
#[pallet::call_index(1)]
pub fn remove_anchor(
origin: OriginFor<T>,
document_id: u128,
document_version: u64,
) -> DispatchResult {
let account_id = ensure_signed(origin)?;
ensure!(
PersonalAnchors::<T>::get(account_id.clone(), (document_id, document_version))
.is_some(),
Error::<T>::PersonalAnchorNotFound
);
let anchor = Anchors::<T>::get((document_id, document_version))
.ok_or(Error::<T>::AnchorNotFound)?;
T::Currency::unreserve(&account_id, anchor.deposit);
Anchors::<T>::remove((document_id, document_version));
PersonalAnchors::<T>::remove(account_id.clone(), (document_id, document_version));
Self::deposit_event(Event::AnchorRemoved {
account_id,
document_id,
document_version,
hash: anchor.hash,
deposit: anchor.deposit,
});
Ok(())
}
#[pallet::weight(T::WeightInfo::set_deposit_value())]
#[pallet::call_index(2)]
pub fn set_deposit_value(origin: OriginFor<T>, new_deposit: T::Balance) -> DispatchResult {
T::AdminOrigin::ensure_origin(origin)?;
<AnchorDeposit<T>>::set(new_deposit);
Self::deposit_event(Event::DepositSet { new_deposit });
Ok(())
}
}
}