123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990#![cfg_attr(not(feature = "std"), no_std)]9192mod benchmarking;93#[cfg(test)]94mod tests;95mod types;96pub mod weights;9798use frame_support::traits::{BalanceStatus, Currency, OnUnbalanced, ReservableCurrency};99use sp_runtime::traits::{AppendZerosInput, Hash, Saturating, StaticLookup, Zero};100use sp_std::prelude::*;101pub use weights::WeightInfo;102103pub use pallet::*;104pub use types::{105 Data, IdentityField, IdentityFields, IdentityInfo, Judgement, RegistrarIndex, RegistrarInfo,106 Registration,107};108109pub type BalanceOf<T> =110 <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;111type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<112 <T as frame_system::Config>::AccountId,113>>::NegativeImbalance;114type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;115116#[frame_support::pallet]117pub mod pallet {118 use super::*;119 use frame_support::pallet_prelude::*;120 use frame_system::pallet_prelude::*;121122 #[pallet::config]123 pub trait Config: frame_system::Config {124 125 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;126127 128 type Currency: ReservableCurrency<Self::AccountId>;129130 131 #[pallet::constant]132 type BasicDeposit: Get<BalanceOf<Self>>;133134 135 #[pallet::constant]136 type FieldDeposit: Get<BalanceOf<Self>>;137138 139 140 141 #[pallet::constant]142 type SubAccountDeposit: Get<BalanceOf<Self>>;143144 145 #[pallet::constant]146 type MaxSubAccounts: Get<u32>;147148 149 150 #[pallet::constant]151 type MaxAdditionalFields: Get<u32>;152153 154 155 #[pallet::constant]156 type MaxRegistrars: Get<u32>;157158 159 type Slashed: OnUnbalanced<NegativeImbalanceOf<Self>>;160161 162 type ForceOrigin: EnsureOrigin<Self::RuntimeOrigin>;163164 165 type RegistrarOrigin: EnsureOrigin<Self::RuntimeOrigin>;166167 168 type WeightInfo: WeightInfo;169 }170171 #[pallet::pallet]172 pub struct Pallet<T>(_);173174 175 176 177 #[pallet::storage]178 #[pallet::getter(fn identity)]179 pub(super) type IdentityOf<T: Config> = StorageMap<180 _,181 Twox64Concat,182 T::AccountId,183 Registration<BalanceOf<T>, T::MaxRegistrars, T::MaxAdditionalFields>,184 OptionQuery,185 >;186187 188 189 #[pallet::storage]190 #[pallet::getter(fn super_of)]191 pub(super) type SuperOf<T: Config> =192 StorageMap<_, Blake2_128Concat, T::AccountId, (T::AccountId, Data), OptionQuery>;193194 195 196 197 198 199 #[pallet::storage]200 #[pallet::getter(fn subs_of)]201 pub(super) type SubsOf<T: Config> = StorageMap<202 _,203 Twox64Concat,204 T::AccountId,205 (BalanceOf<T>, BoundedVec<T::AccountId, T::MaxSubAccounts>),206 ValueQuery,207 >;208209 210 211 212 213 #[pallet::storage]214 #[pallet::getter(fn registrars)]215 pub(super) type Registrars<T: Config> = StorageValue<216 _,217 BoundedVec<Option<RegistrarInfo<BalanceOf<T>, T::AccountId>>, T::MaxRegistrars>,218 ValueQuery,219 >;220221 #[pallet::error]222 pub enum Error<T> {223 224 TooManySubAccounts,225 226 NotFound,227 228 NotNamed,229 230 EmptyIndex,231 232 FeeChanged,233 234 NoIdentity,235 236 StickyJudgement,237 238 JudgementGiven,239 240 InvalidJudgement,241 242 InvalidIndex,243 244 InvalidTarget,245 246 TooManyFields,247 248 TooManyRegistrars,249 250 AlreadyClaimed,251 252 NotSub,253 254 NotOwned,255 256 JudgementForDifferentIdentity,257 258 JudgementPaymentFailed,259 }260261 #[pallet::event]262 #[pallet::generate_deposit(pub(super) fn deposit_event)]263 pub enum Event<T: Config> {264 265 IdentitySet { who: T::AccountId },266 267 IdentityCleared {268 who: T::AccountId,269 deposit: BalanceOf<T>,270 },271 272 IdentityKilled {273 who: T::AccountId,274 deposit: BalanceOf<T>,275 },276 277 IdentitiesInserted { amount: u32 },278 279 IdentitiesRemoved { amount: u32 },280 281 JudgementRequested {282 who: T::AccountId,283 registrar_index: RegistrarIndex,284 },285 286 JudgementUnrequested {287 who: T::AccountId,288 registrar_index: RegistrarIndex,289 },290 291 JudgementGiven {292 target: T::AccountId,293 registrar_index: RegistrarIndex,294 },295 296 RegistrarAdded { registrar_index: RegistrarIndex },297 298 SubIdentityAdded {299 sub: T::AccountId,300 main: T::AccountId,301 deposit: BalanceOf<T>,302 },303 304 SubIdentityRemoved {305 sub: T::AccountId,306 main: T::AccountId,307 deposit: BalanceOf<T>,308 },309 310 311 SubIdentityRevoked {312 sub: T::AccountId,313 main: T::AccountId,314 deposit: BalanceOf<T>,315 },316 317 SubIdentitiesInserted { amount: u32 },318 }319320 #[pallet::call]321 322 impl<T: Config> Pallet<T> {323 324 325 326 327 328 329 330 331 332 333 334 335 336 #[pallet::call_index(0)]337 #[pallet::weight(T::WeightInfo::add_registrar(T::MaxRegistrars::get()))]338 pub fn add_registrar(339 origin: OriginFor<T>,340 account: AccountIdLookupOf<T>,341 ) -> DispatchResultWithPostInfo {342 T::RegistrarOrigin::ensure_origin(origin)?;343 let account = T::Lookup::lookup(account)?;344345 let (i, registrar_count) = <Registrars<T>>::try_mutate(346 |registrars| -> Result<(RegistrarIndex, usize), DispatchError> {347 registrars348 .try_push(Some(RegistrarInfo {349 account,350 fee: Zero::zero(),351 fields: Default::default(),352 }))353 .map_err(|_| Error::<T>::TooManyRegistrars)?;354 Ok(((registrars.len() - 1) as RegistrarIndex, registrars.len()))355 },356 )?;357358 Self::deposit_event(Event::RegistrarAdded { registrar_index: i });359360 Ok(Some(T::WeightInfo::add_registrar(registrar_count as u32)).into())361 }362363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 #[pallet::call_index(1)]383 #[pallet::weight( T::WeightInfo::set_identity(384 T::MaxRegistrars::get(), 385 T::MaxAdditionalFields::get(), 386 ))]387 pub fn set_identity(388 origin: OriginFor<T>,389 info: Box<IdentityInfo<T::MaxAdditionalFields>>,390 ) -> DispatchResultWithPostInfo {391 let sender = ensure_signed(origin)?;392 let extra_fields = info.additional.len() as u32;393 ensure!(394 extra_fields <= T::MaxAdditionalFields::get(),395 Error::<T>::TooManyFields396 );397 let fd = <BalanceOf<T>>::from(extra_fields) * T::FieldDeposit::get();398399 let mut id = match <IdentityOf<T>>::get(&sender) {400 Some(mut id) => {401 402 id.judgements.retain(|j| j.1.is_sticky());403 id.info = *info;404 id405 }406 None => Registration {407 info: *info,408 judgements: BoundedVec::default(),409 deposit: Zero::zero(),410 },411 };412413 let old_deposit = id.deposit;414 id.deposit = T::BasicDeposit::get() + fd;415 if id.deposit > old_deposit {416 T::Currency::reserve(&sender, id.deposit - old_deposit)?;417 }418 if old_deposit > id.deposit {419 let err_amount = T::Currency::unreserve(&sender, old_deposit - id.deposit);420 debug_assert!(err_amount.is_zero());421 }422423 let judgements = id.judgements.len();424 <IdentityOf<T>>::insert(&sender, id);425 Self::deposit_event(Event::IdentitySet { who: sender });426427 Ok(Some(T::WeightInfo::set_identity(428 judgements as u32, 429 extra_fields, 430 ))431 .into())432 }433434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 #[pallet::call_index(2)]462 #[pallet::weight(T::WeightInfo::set_subs_old(T::MaxSubAccounts::get()) 463 .saturating_add(T::WeightInfo::set_subs_new(subs.len() as u32)) 464 )]465 pub fn set_subs(466 origin: OriginFor<T>,467 subs: Vec<(T::AccountId, Data)>,468 ) -> DispatchResultWithPostInfo {469 let sender = ensure_signed(origin)?;470 ensure!(<IdentityOf<T>>::contains_key(&sender), Error::<T>::NotFound);471 ensure!(472 subs.len() <= T::MaxSubAccounts::get() as usize,473 Error::<T>::TooManySubAccounts474 );475476 let (old_deposit, old_ids) = <SubsOf<T>>::get(&sender);477 let new_deposit = T::SubAccountDeposit::get() * <BalanceOf<T>>::from(subs.len() as u32);478479 let not_other_sub = subs480 .iter()481 .filter_map(|i| SuperOf::<T>::get(&i.0))482 .all(|i| i.0 == sender);483 ensure!(not_other_sub, Error::<T>::AlreadyClaimed);484485 if old_deposit < new_deposit {486 T::Currency::reserve(&sender, new_deposit - old_deposit)?;487 } else if old_deposit > new_deposit {488 let err_amount = T::Currency::unreserve(&sender, old_deposit - new_deposit);489 debug_assert!(err_amount.is_zero());490 }491 492493 for s in old_ids.iter() {494 <SuperOf<T>>::remove(s);495 }496 let mut ids = BoundedVec::<T::AccountId, T::MaxSubAccounts>::default();497 for (id, name) in subs {498 <SuperOf<T>>::insert(&id, (sender.clone(), name));499 ids.try_push(id)500 .expect("subs length is less than T::MaxSubAccounts; qed");501 }502 let new_subs = ids.len();503504 if ids.is_empty() {505 <SubsOf<T>>::remove(&sender);506 } else {507 <SubsOf<T>>::insert(&sender, (new_deposit, ids));508 }509510 Ok(Some(511 T::WeightInfo::set_subs_old(old_ids.len() as u32) 512 513 .saturating_add(T::WeightInfo::set_subs_new(new_subs as u32)),514 )515 .into())516 }517518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 #[pallet::call_index(3)]537 #[pallet::weight(T::WeightInfo::clear_identity(538 T::MaxRegistrars::get(), 539 T::MaxSubAccounts::get(), 540 T::MaxAdditionalFields::get(), 541 ))]542 pub fn clear_identity(origin: OriginFor<T>) -> DispatchResultWithPostInfo {543 let sender = ensure_signed(origin)?;544545 let (subs_deposit, sub_ids) = <SubsOf<T>>::take(&sender);546 let id = <IdentityOf<T>>::take(&sender).ok_or(Error::<T>::NotNamed)?;547 let deposit = id.total_deposit() + subs_deposit;548 for sub in sub_ids.iter() {549 <SuperOf<T>>::remove(sub);550 }551552 let err_amount = T::Currency::unreserve(&sender, deposit);553 debug_assert!(err_amount.is_zero());554555 Self::deposit_event(Event::IdentityCleared {556 who: sender,557 deposit,558 });559560 Ok(Some(T::WeightInfo::clear_identity(561 id.judgements.len() as u32, 562 sub_ids.len() as u32, 563 id.info.additional.len() as u32, 564 ))565 .into())566 }567568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 #[pallet::call_index(4)]592 #[pallet::weight(T::WeightInfo::request_judgement(593 T::MaxRegistrars::get(), 594 T::MaxAdditionalFields::get(), 595 ))]596 pub fn request_judgement(597 origin: OriginFor<T>,598 #[pallet::compact] reg_index: RegistrarIndex,599 #[pallet::compact] max_fee: BalanceOf<T>,600 ) -> DispatchResultWithPostInfo {601 let sender = ensure_signed(origin)?;602 let registrars = <Registrars<T>>::get();603 let registrar = registrars604 .get(reg_index as usize)605 .and_then(Option::as_ref)606 .ok_or(Error::<T>::EmptyIndex)?;607 ensure!(max_fee >= registrar.fee, Error::<T>::FeeChanged);608 let mut id = <IdentityOf<T>>::get(&sender).ok_or(Error::<T>::NoIdentity)?;609610 let item = (reg_index, Judgement::FeePaid(registrar.fee));611 match id.judgements.binary_search_by_key(®_index, |x| x.0) {612 Ok(i) => {613 if id.judgements[i].1.is_sticky() {614 return Err(Error::<T>::StickyJudgement.into());615 } else {616 id.judgements[i] = item617 }618 }619 Err(i) => id620 .judgements621 .try_insert(i, item)622 .map_err(|_| Error::<T>::TooManyRegistrars)?,623 }624625 T::Currency::reserve(&sender, registrar.fee)?;626627 let judgements = id.judgements.len();628 let extra_fields = id.info.additional.len();629 <IdentityOf<T>>::insert(&sender, id);630631 Self::deposit_event(Event::JudgementRequested {632 who: sender,633 registrar_index: reg_index,634 });635636 Ok(Some(T::WeightInfo::request_judgement(637 judgements as u32,638 extra_fields as u32,639 ))640 .into())641 }642643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 #[pallet::call_index(5)]661 #[pallet::weight(T::WeightInfo::cancel_request(662 T::MaxRegistrars::get(), 663 T::MaxAdditionalFields::get(), 664 ))]665 pub fn cancel_request(666 origin: OriginFor<T>,667 reg_index: RegistrarIndex,668 ) -> DispatchResultWithPostInfo {669 let sender = ensure_signed(origin)?;670 let mut id = <IdentityOf<T>>::get(&sender).ok_or(Error::<T>::NoIdentity)?;671672 let pos = id673 .judgements674 .binary_search_by_key(®_index, |x| x.0)675 .map_err(|_| Error::<T>::NotFound)?;676 let fee = if let Judgement::FeePaid(fee) = id.judgements.remove(pos).1 {677 fee678 } else {679 return Err(Error::<T>::JudgementGiven.into());680 };681682 let err_amount = T::Currency::unreserve(&sender, fee);683 debug_assert!(err_amount.is_zero());684 let judgements = id.judgements.len();685 let extra_fields = id.info.additional.len();686 <IdentityOf<T>>::insert(&sender, id);687688 Self::deposit_event(Event::JudgementUnrequested {689 who: sender,690 registrar_index: reg_index,691 });692693 Ok(Some(T::WeightInfo::cancel_request(694 judgements as u32,695 extra_fields as u32,696 ))697 .into())698 }699700 701 702 703 704 705 706 707 708 709 710 711 712 713 #[pallet::call_index(6)]714 #[pallet::weight(T::WeightInfo::set_fee(T::MaxRegistrars::get()))] 715 pub fn set_fee(716 origin: OriginFor<T>,717 #[pallet::compact] index: RegistrarIndex,718 #[pallet::compact] fee: BalanceOf<T>,719 ) -> DispatchResultWithPostInfo {720 let who = ensure_signed(origin)?;721722 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {723 rs.get_mut(index as usize)724 .and_then(|x| x.as_mut())725 .and_then(|r| {726 if r.account == who {727 r.fee = fee;728 Some(())729 } else {730 None731 }732 })733 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;734 Ok(rs.len())735 })?;736 Ok(Some(T::WeightInfo::set_fee(registrars as u32)).into()) 737 }738739 740 741 742 743 744 745 746 747 748 749 750 751 752 #[pallet::call_index(7)]753 #[pallet::weight(T::WeightInfo::set_account_id(T::MaxRegistrars::get()))] 754 pub fn set_account_id(755 origin: OriginFor<T>,756 #[pallet::compact] index: RegistrarIndex,757 new: AccountIdLookupOf<T>,758 ) -> DispatchResultWithPostInfo {759 let who = ensure_signed(origin)?;760 let new = T::Lookup::lookup(new)?;761762 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {763 rs.get_mut(index as usize)764 .and_then(|x| x.as_mut())765 .and_then(|r| {766 if r.account == who {767 r.account = new;768 Some(())769 } else {770 None771 }772 })773 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;774 Ok(rs.len())775 })?;776 Ok(Some(T::WeightInfo::set_account_id(registrars as u32)).into()) 777 }778779 780 781 782 783 784 785 786 787 788 789 790 791 792 #[pallet::call_index(8)]793 #[pallet::weight(T::WeightInfo::set_fields(T::MaxRegistrars::get()))] 794 pub fn set_fields(795 origin: OriginFor<T>,796 #[pallet::compact] index: RegistrarIndex,797 fields: IdentityFields,798 ) -> DispatchResultWithPostInfo {799 let who = ensure_signed(origin)?;800801 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {802 rs.get_mut(index as usize)803 .and_then(|x| x.as_mut())804 .and_then(|r| {805 if r.account == who {806 r.fields = fields;807 Some(())808 } else {809 None810 }811 })812 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;813 Ok(rs.len())814 })?;815 Ok(Some(T::WeightInfo::set_fields(816 registrars as u32, 817 ))818 .into())819 }820821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 #[pallet::call_index(9)]842 #[pallet::weight(T::WeightInfo::provide_judgement(843 T::MaxRegistrars::get(), 844 T::MaxAdditionalFields::get(), 845 ))]846 pub fn provide_judgement(847 origin: OriginFor<T>,848 #[pallet::compact] reg_index: RegistrarIndex,849 target: AccountIdLookupOf<T>,850 judgement: Judgement<BalanceOf<T>>,851 identity: T::Hash,852 ) -> DispatchResultWithPostInfo {853 let sender = ensure_signed(origin)?;854 let target = T::Lookup::lookup(target)?;855 ensure!(!judgement.has_deposit(), Error::<T>::InvalidJudgement);856 <Registrars<T>>::get()857 .get(reg_index as usize)858 .and_then(Option::as_ref)859 .filter(|r| r.account == sender)860 .ok_or(Error::<T>::InvalidIndex)?;861 let mut id = <IdentityOf<T>>::get(&target).ok_or(Error::<T>::InvalidTarget)?;862863 if T::Hashing::hash_of(&id.info) != identity {864 return Err(Error::<T>::JudgementForDifferentIdentity.into());865 }866867 let item = (reg_index, judgement);868 match id.judgements.binary_search_by_key(®_index, |x| x.0) {869 Ok(position) => {870 if let Judgement::FeePaid(fee) = id.judgements[position].1 {871 T::Currency::repatriate_reserved(872 &target,873 &sender,874 fee,875 BalanceStatus::Free,876 )877 .map_err(|_| Error::<T>::JudgementPaymentFailed)?;878 }879 id.judgements[position] = item880 }881 Err(position) => id882 .judgements883 .try_insert(position, item)884 .map_err(|_| Error::<T>::TooManyRegistrars)?,885 }886887 let judgements = id.judgements.len();888 let extra_fields = id.info.additional.len();889 <IdentityOf<T>>::insert(&target, id);890 Self::deposit_event(Event::JudgementGiven {891 target,892 registrar_index: reg_index,893 });894895 Ok(Some(T::WeightInfo::provide_judgement(896 judgements as u32,897 extra_fields as u32,898 ))899 .into())900 }901902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 #[pallet::call_index(10)]922 #[pallet::weight(T::WeightInfo::kill_identity(923 T::MaxRegistrars::get(), 924 T::MaxSubAccounts::get(), 925 T::MaxAdditionalFields::get(), 926 ))]927 pub fn kill_identity(928 origin: OriginFor<T>,929 target: AccountIdLookupOf<T>,930 ) -> DispatchResultWithPostInfo {931 T::ForceOrigin::ensure_origin(origin)?;932933 934 let target = T::Lookup::lookup(target)?;935 936 let (subs_deposit, sub_ids) = <SubsOf<T>>::take(&target);937 let id = <IdentityOf<T>>::take(&target).ok_or(Error::<T>::NotNamed)?;938 let deposit = id.total_deposit() + subs_deposit;939 for sub in sub_ids.iter() {940 <SuperOf<T>>::remove(sub);941 }942 943 T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit).0);944945 Self::deposit_event(Event::IdentityKilled {946 who: target,947 deposit,948 });949950 Ok(Some(T::WeightInfo::kill_identity(951 id.judgements.len() as u32, 952 sub_ids.len() as u32, 953 id.info.additional.len() as u32, 954 ))955 .into())956 }957958 959 960 961 962 963 964 965 #[pallet::call_index(11)]966 #[pallet::weight(T::WeightInfo::add_sub(T::MaxSubAccounts::get()))]967 pub fn add_sub(968 origin: OriginFor<T>,969 sub: AccountIdLookupOf<T>,970 data: Data,971 ) -> DispatchResult {972 let sender = ensure_signed(origin)?;973 let sub = T::Lookup::lookup(sub)?;974 ensure!(975 IdentityOf::<T>::contains_key(&sender),976 Error::<T>::NoIdentity977 );978979 980 ensure!(981 !SuperOf::<T>::contains_key(&sub),982 Error::<T>::AlreadyClaimed983 );984985 SubsOf::<T>::try_mutate(&sender, |(ref mut subs_deposit, ref mut sub_ids)| {986 987 ensure!(988 sub_ids.len() < T::MaxSubAccounts::get() as usize,989 Error::<T>::TooManySubAccounts990 );991 let deposit = T::SubAccountDeposit::get();992 T::Currency::reserve(&sender, deposit)?;993994 SuperOf::<T>::insert(&sub, (sender.clone(), data));995 sub_ids996 .try_push(sub.clone())997 .expect("sub ids length checked above; qed");998 *subs_deposit = subs_deposit.saturating_add(deposit);9991000 Self::deposit_event(Event::SubIdentityAdded {1001 sub,1002 main: sender.clone(),1003 deposit,1004 });1005 Ok(())1006 })1007 }10081009 1010 1011 1012 1013 #[pallet::call_index(12)]1014 #[pallet::weight(T::WeightInfo::rename_sub(T::MaxSubAccounts::get()))]1015 pub fn rename_sub(1016 origin: OriginFor<T>,1017 sub: AccountIdLookupOf<T>,1018 data: Data,1019 ) -> DispatchResult {1020 let sender = ensure_signed(origin)?;1021 let sub = T::Lookup::lookup(sub)?;1022 ensure!(1023 IdentityOf::<T>::contains_key(&sender),1024 Error::<T>::NoIdentity1025 );1026 ensure!(1027 SuperOf::<T>::get(&sub).map_or(false, |x| x.0 == sender),1028 Error::<T>::NotOwned1029 );1030 SuperOf::<T>::insert(&sub, (sender, data));1031 Ok(())1032 }10331034 1035 1036 1037 1038 1039 1040 1041 #[pallet::call_index(13)]1042 #[pallet::weight(T::WeightInfo::remove_sub(T::MaxSubAccounts::get()))]1043 pub fn remove_sub(origin: OriginFor<T>, sub: AccountIdLookupOf<T>) -> DispatchResult {1044 let sender = ensure_signed(origin)?;1045 ensure!(1046 IdentityOf::<T>::contains_key(&sender),1047 Error::<T>::NoIdentity1048 );1049 let sub = T::Lookup::lookup(sub)?;1050 let (sup, _) = SuperOf::<T>::get(&sub).ok_or(Error::<T>::NotSub)?;1051 ensure!(sup == sender, Error::<T>::NotOwned);1052 SuperOf::<T>::remove(&sub);1053 SubsOf::<T>::mutate(&sup, |(ref mut subs_deposit, ref mut sub_ids)| {1054 sub_ids.retain(|x| x != &sub);1055 let deposit = T::SubAccountDeposit::get().min(*subs_deposit);1056 *subs_deposit -= deposit;1057 let err_amount = T::Currency::unreserve(&sender, deposit);1058 debug_assert!(err_amount.is_zero());1059 Self::deposit_event(Event::SubIdentityRemoved {1060 sub,1061 main: sender,1062 deposit,1063 });1064 });1065 Ok(())1066 }10671068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 #[pallet::call_index(14)]1079 #[pallet::weight(T::WeightInfo::quit_sub(T::MaxSubAccounts::get()))]1080 pub fn quit_sub(origin: OriginFor<T>) -> DispatchResult {1081 let sender = ensure_signed(origin)?;1082 let (sup, _) = SuperOf::<T>::take(&sender).ok_or(Error::<T>::NotSub)?;1083 SubsOf::<T>::mutate(&sup, |(ref mut subs_deposit, ref mut sub_ids)| {1084 sub_ids.retain(|x| x != &sender);1085 let deposit = T::SubAccountDeposit::get().min(*subs_deposit);1086 *subs_deposit -= deposit;1087 let _ =1088 T::Currency::repatriate_reserved(&sup, &sender, deposit, BalanceStatus::Free);1089 Self::deposit_event(Event::SubIdentityRevoked {1090 sub: sender,1091 main: sup.clone(),1092 deposit,1093 });1094 });1095 Ok(())1096 }10971098 1099 1100 1101 1102 1103 #[pallet::call_index(15)]1104 #[pallet::weight(T::WeightInfo::force_insert_identities(1105 T::MaxAdditionalFields::get(), 1106 identities.len() as u32, 1107 ))]1108 pub fn force_insert_identities(1109 origin: OriginFor<T>,1110 identities: Vec<(1111 T::AccountId,1112 Registration<BalanceOf<T>, T::MaxRegistrars, T::MaxAdditionalFields>,1113 )>,1114 ) -> DispatchResult {1115 T::ForceOrigin::ensure_origin(origin)?;1116 for identity in identities.clone() {1117 IdentityOf::<T>::insert(identity.0, identity.1);1118 }1119 Self::deposit_event(Event::IdentitiesInserted {1120 amount: identities.len() as u32,1121 });1122 Ok(())1123 }11241125 1126 1127 1128 1129 1130 #[pallet::call_index(16)]1131 #[pallet::weight(T::WeightInfo::force_remove_identities(1132 T::MaxAdditionalFields::get(), 1133 identities.len() as u32, 1134 ))]1135 pub fn force_remove_identities(1136 origin: OriginFor<T>,1137 identities: Vec<T::AccountId>,1138 ) -> DispatchResult {1139 T::ForceOrigin::ensure_origin(origin)?;1140 for identity in identities.clone() {1141 let (_, sub_ids) = <SubsOf<T>>::take(&identity);1142 <IdentityOf<T>>::remove(&identity);1143 for sub in sub_ids.iter() {1144 <SuperOf<T>>::remove(sub);1145 }1146 }1147 Self::deposit_event(Event::IdentitiesRemoved {1148 amount: identities.len() as u32,1149 });1150 Ok(())1151 }11521153 1154 1155 1156 1157 1158 #[pallet::call_index(17)]1159 #[pallet::weight(T::WeightInfo::force_set_subs(1160 T::MaxSubAccounts::get(), 1161 subs.len() as u32, 1162 ))]1163 pub fn force_set_subs(1164 origin: OriginFor<T>,1165 subs: Vec<(1166 T::AccountId,1167 (1168 BalanceOf<T>,1169 BoundedVec<(T::AccountId, Data), T::MaxSubAccounts>,1170 ),1171 )>,1172 ) -> DispatchResult {1173 T::ForceOrigin::ensure_origin(origin)?;1174 for identity in subs.clone() {1175 let account = identity.0;1176 let (_, old_subs) = <SubsOf<T>>::get(&account);1177 for old_sub in old_subs {1178 <SuperOf<T>>::remove(old_sub);1179 }11801181 let mut ids = BoundedVec::<T::AccountId, T::MaxSubAccounts>::default();1182 for (id, name) in identity.1 .1 {1183 <SuperOf<T>>::insert(&id, (account.clone(), name));1184 ids.try_push(id)1185 .expect("subs length is less than T::MaxSubAccounts; qed");1186 }11871188 if ids.is_empty() {1189 <SubsOf<T>>::remove(&account);1190 } else {1191 <SubsOf<T>>::insert(account, (identity.1 .0, ids));1192 }1193 }1194 Self::deposit_event(Event::SubIdentitiesInserted {1195 amount: subs.len() as u32,1196 });1197 Ok(())1198 }1199 }1200}12011202impl<T: Config> Pallet<T> {1203 1204 pub fn subs(who: &T::AccountId) -> Vec<(T::AccountId, Data)> {1205 SubsOf::<T>::get(who)1206 .11207 .into_iter()1208 .filter_map(|a| SuperOf::<T>::get(&a).map(|x| (a, x.1)))1209 .collect()1210 }12111212 1213 pub fn has_identity(who: &T::AccountId, fields: u64) -> bool {1214 IdentityOf::<T>::get(who).map_or(false, |registration| {1215 (registration.info.fields().0.bits() & fields) == fields1216 })1217 }1218}