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 #[pallet::generate_store(pub(super) trait Store)]173 pub struct Pallet<T>(_);174175 176 177 178 #[pallet::storage]179 #[pallet::getter(fn identity)]180 pub(super) type IdentityOf<T: Config> = StorageMap<181 _,182 Twox64Concat,183 T::AccountId,184 Registration<BalanceOf<T>, T::MaxRegistrars, T::MaxAdditionalFields>,185 OptionQuery,186 >;187188 189 190 #[pallet::storage]191 #[pallet::getter(fn super_of)]192 pub(super) type SuperOf<T: Config> =193 StorageMap<_, Blake2_128Concat, T::AccountId, (T::AccountId, Data), OptionQuery>;194195 196 197 198 199 200 #[pallet::storage]201 #[pallet::getter(fn subs_of)]202 pub(super) type SubsOf<T: Config> = StorageMap<203 _,204 Twox64Concat,205 T::AccountId,206 (BalanceOf<T>, BoundedVec<T::AccountId, T::MaxSubAccounts>),207 ValueQuery,208 >;209210 211 212 213 214 #[pallet::storage]215 #[pallet::getter(fn registrars)]216 pub(super) type Registrars<T: Config> = StorageValue<217 _,218 BoundedVec<Option<RegistrarInfo<BalanceOf<T>, T::AccountId>>, T::MaxRegistrars>,219 ValueQuery,220 >;221222 #[pallet::error]223 pub enum Error<T> {224 225 TooManySubAccounts,226 227 NotFound,228 229 NotNamed,230 231 EmptyIndex,232 233 FeeChanged,234 235 NoIdentity,236 237 StickyJudgement,238 239 JudgementGiven,240 241 InvalidJudgement,242 243 InvalidIndex,244 245 InvalidTarget,246 247 TooManyFields,248 249 TooManyRegistrars,250 251 AlreadyClaimed,252 253 NotSub,254 255 NotOwned,256 257 JudgementForDifferentIdentity,258 259 JudgementPaymentFailed,260 }261262 #[pallet::event]263 #[pallet::generate_deposit(pub(super) fn deposit_event)]264 pub enum Event<T: Config> {265 266 IdentitySet { who: T::AccountId },267 268 IdentityCleared {269 who: T::AccountId,270 deposit: BalanceOf<T>,271 },272 273 IdentityKilled {274 who: T::AccountId,275 deposit: BalanceOf<T>,276 },277 278 IdentitiesInserted { amount: u32 },279 280 IdentitiesRemoved { amount: u32 },281 282 JudgementRequested {283 who: T::AccountId,284 registrar_index: RegistrarIndex,285 },286 287 JudgementUnrequested {288 who: T::AccountId,289 registrar_index: RegistrarIndex,290 },291 292 JudgementGiven {293 target: T::AccountId,294 registrar_index: RegistrarIndex,295 },296 297 RegistrarAdded { registrar_index: RegistrarIndex },298 299 SubIdentityAdded {300 sub: T::AccountId,301 main: T::AccountId,302 deposit: BalanceOf<T>,303 },304 305 SubIdentityRemoved {306 sub: T::AccountId,307 main: T::AccountId,308 deposit: BalanceOf<T>,309 },310 311 312 SubIdentityRevoked {313 sub: T::AccountId,314 main: T::AccountId,315 deposit: BalanceOf<T>,316 },317 318 SubIdentitiesInserted { amount: u32 },319 }320321 #[pallet::call]322 323 impl<T: Config> Pallet<T> {324 325 326 327 328 329 330 331 332 333 334 335 336 337 #[pallet::call_index(0)]338 #[pallet::weight(T::WeightInfo::add_registrar(T::MaxRegistrars::get()))]339 pub fn add_registrar(340 origin: OriginFor<T>,341 account: AccountIdLookupOf<T>,342 ) -> DispatchResultWithPostInfo {343 T::RegistrarOrigin::ensure_origin(origin)?;344 let account = T::Lookup::lookup(account)?;345346 let (i, registrar_count) = <Registrars<T>>::try_mutate(347 |registrars| -> Result<(RegistrarIndex, usize), DispatchError> {348 registrars349 .try_push(Some(RegistrarInfo {350 account,351 fee: Zero::zero(),352 fields: Default::default(),353 }))354 .map_err(|_| Error::<T>::TooManyRegistrars)?;355 Ok(((registrars.len() - 1) as RegistrarIndex, registrars.len()))356 },357 )?;358359 Self::deposit_event(Event::RegistrarAdded { registrar_index: i });360361 Ok(Some(T::WeightInfo::add_registrar(registrar_count as u32)).into())362 }363364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 #[pallet::call_index(1)]384 #[pallet::weight( T::WeightInfo::set_identity(385 T::MaxRegistrars::get(), 386 T::MaxAdditionalFields::get(), 387 ))]388 pub fn set_identity(389 origin: OriginFor<T>,390 info: Box<IdentityInfo<T::MaxAdditionalFields>>,391 ) -> DispatchResultWithPostInfo {392 let sender = ensure_signed(origin)?;393 let extra_fields = info.additional.len() as u32;394 ensure!(395 extra_fields <= T::MaxAdditionalFields::get(),396 Error::<T>::TooManyFields397 );398 let fd = <BalanceOf<T>>::from(extra_fields) * T::FieldDeposit::get();399400 let mut id = match <IdentityOf<T>>::get(&sender) {401 Some(mut id) => {402 403 id.judgements.retain(|j| j.1.is_sticky());404 id.info = *info;405 id406 }407 None => Registration {408 info: *info,409 judgements: BoundedVec::default(),410 deposit: Zero::zero(),411 },412 };413414 let old_deposit = id.deposit;415 id.deposit = T::BasicDeposit::get() + fd;416 if id.deposit > old_deposit {417 T::Currency::reserve(&sender, id.deposit - old_deposit)?;418 }419 if old_deposit > id.deposit {420 let err_amount = T::Currency::unreserve(&sender, old_deposit - id.deposit);421 debug_assert!(err_amount.is_zero());422 }423424 let judgements = id.judgements.len();425 <IdentityOf<T>>::insert(&sender, id);426 Self::deposit_event(Event::IdentitySet { who: sender });427428 Ok(Some(T::WeightInfo::set_identity(429 judgements as u32, 430 extra_fields, 431 ))432 .into())433 }434435 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 462 #[pallet::call_index(2)]463 #[pallet::weight(T::WeightInfo::set_subs_old(T::MaxSubAccounts::get()) 464 .saturating_add(T::WeightInfo::set_subs_new(subs.len() as u32)) 465 )]466 pub fn set_subs(467 origin: OriginFor<T>,468 subs: Vec<(T::AccountId, Data)>,469 ) -> DispatchResultWithPostInfo {470 let sender = ensure_signed(origin)?;471 ensure!(<IdentityOf<T>>::contains_key(&sender), Error::<T>::NotFound);472 ensure!(473 subs.len() <= T::MaxSubAccounts::get() as usize,474 Error::<T>::TooManySubAccounts475 );476477 let (old_deposit, old_ids) = <SubsOf<T>>::get(&sender);478 let new_deposit = T::SubAccountDeposit::get() * <BalanceOf<T>>::from(subs.len() as u32);479480 let not_other_sub = subs481 .iter()482 .filter_map(|i| SuperOf::<T>::get(&i.0))483 .all(|i| i.0 == sender);484 ensure!(not_other_sub, Error::<T>::AlreadyClaimed);485486 if old_deposit < new_deposit {487 T::Currency::reserve(&sender, new_deposit - old_deposit)?;488 } else if old_deposit > new_deposit {489 let err_amount = T::Currency::unreserve(&sender, old_deposit - new_deposit);490 debug_assert!(err_amount.is_zero());491 }492 493494 for s in old_ids.iter() {495 <SuperOf<T>>::remove(s);496 }497 let mut ids = BoundedVec::<T::AccountId, T::MaxSubAccounts>::default();498 for (id, name) in subs {499 <SuperOf<T>>::insert(&id, (sender.clone(), name));500 ids.try_push(id)501 .expect("subs length is less than T::MaxSubAccounts; qed");502 }503 let new_subs = ids.len();504505 if ids.is_empty() {506 <SubsOf<T>>::remove(&sender);507 } else {508 <SubsOf<T>>::insert(&sender, (new_deposit, ids));509 }510511 Ok(Some(512 T::WeightInfo::set_subs_old(old_ids.len() as u32) 513 514 .saturating_add(T::WeightInfo::set_subs_new(new_subs as u32)),515 )516 .into())517 }518519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 #[pallet::call_index(3)]538 #[pallet::weight(T::WeightInfo::clear_identity(539 T::MaxRegistrars::get(), 540 T::MaxSubAccounts::get(), 541 T::MaxAdditionalFields::get(), 542 ))]543 pub fn clear_identity(origin: OriginFor<T>) -> DispatchResultWithPostInfo {544 let sender = ensure_signed(origin)?;545546 let (subs_deposit, sub_ids) = <SubsOf<T>>::take(&sender);547 let id = <IdentityOf<T>>::take(&sender).ok_or(Error::<T>::NotNamed)?;548 let deposit = id.total_deposit() + subs_deposit;549 for sub in sub_ids.iter() {550 <SuperOf<T>>::remove(sub);551 }552553 let err_amount = T::Currency::unreserve(&sender, deposit);554 debug_assert!(err_amount.is_zero());555556 Self::deposit_event(Event::IdentityCleared {557 who: sender,558 deposit,559 });560561 Ok(Some(T::WeightInfo::clear_identity(562 id.judgements.len() as u32, 563 sub_ids.len() as u32, 564 id.info.additional.len() as u32, 565 ))566 .into())567 }568569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 #[pallet::call_index(4)]593 #[pallet::weight(T::WeightInfo::request_judgement(594 T::MaxRegistrars::get(), 595 T::MaxAdditionalFields::get(), 596 ))]597 pub fn request_judgement(598 origin: OriginFor<T>,599 #[pallet::compact] reg_index: RegistrarIndex,600 #[pallet::compact] max_fee: BalanceOf<T>,601 ) -> DispatchResultWithPostInfo {602 let sender = ensure_signed(origin)?;603 let registrars = <Registrars<T>>::get();604 let registrar = registrars605 .get(reg_index as usize)606 .and_then(Option::as_ref)607 .ok_or(Error::<T>::EmptyIndex)?;608 ensure!(max_fee >= registrar.fee, Error::<T>::FeeChanged);609 let mut id = <IdentityOf<T>>::get(&sender).ok_or(Error::<T>::NoIdentity)?;610611 let item = (reg_index, Judgement::FeePaid(registrar.fee));612 match id.judgements.binary_search_by_key(®_index, |x| x.0) {613 Ok(i) => {614 if id.judgements[i].1.is_sticky() {615 return Err(Error::<T>::StickyJudgement.into());616 } else {617 id.judgements[i] = item618 }619 }620 Err(i) => id621 .judgements622 .try_insert(i, item)623 .map_err(|_| Error::<T>::TooManyRegistrars)?,624 }625626 T::Currency::reserve(&sender, registrar.fee)?;627628 let judgements = id.judgements.len();629 let extra_fields = id.info.additional.len();630 <IdentityOf<T>>::insert(&sender, id);631632 Self::deposit_event(Event::JudgementRequested {633 who: sender,634 registrar_index: reg_index,635 });636637 Ok(Some(T::WeightInfo::request_judgement(638 judgements as u32,639 extra_fields as u32,640 ))641 .into())642 }643644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 #[pallet::call_index(5)]662 #[pallet::weight(T::WeightInfo::cancel_request(663 T::MaxRegistrars::get(), 664 T::MaxAdditionalFields::get(), 665 ))]666 pub fn cancel_request(667 origin: OriginFor<T>,668 reg_index: RegistrarIndex,669 ) -> DispatchResultWithPostInfo {670 let sender = ensure_signed(origin)?;671 let mut id = <IdentityOf<T>>::get(&sender).ok_or(Error::<T>::NoIdentity)?;672673 let pos = id674 .judgements675 .binary_search_by_key(®_index, |x| x.0)676 .map_err(|_| Error::<T>::NotFound)?;677 let fee = if let Judgement::FeePaid(fee) = id.judgements.remove(pos).1 {678 fee679 } else {680 return Err(Error::<T>::JudgementGiven.into());681 };682683 let err_amount = T::Currency::unreserve(&sender, fee);684 debug_assert!(err_amount.is_zero());685 let judgements = id.judgements.len();686 let extra_fields = id.info.additional.len();687 <IdentityOf<T>>::insert(&sender, id);688689 Self::deposit_event(Event::JudgementUnrequested {690 who: sender,691 registrar_index: reg_index,692 });693694 Ok(Some(T::WeightInfo::cancel_request(695 judgements as u32,696 extra_fields as u32,697 ))698 .into())699 }700701 702 703 704 705 706 707 708 709 710 711 712 713 714 #[pallet::call_index(6)]715 #[pallet::weight(T::WeightInfo::set_fee(T::MaxRegistrars::get()))] 716 pub fn set_fee(717 origin: OriginFor<T>,718 #[pallet::compact] index: RegistrarIndex,719 #[pallet::compact] fee: BalanceOf<T>,720 ) -> DispatchResultWithPostInfo {721 let who = ensure_signed(origin)?;722723 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {724 rs.get_mut(index as usize)725 .and_then(|x| x.as_mut())726 .and_then(|r| {727 if r.account == who {728 r.fee = fee;729 Some(())730 } else {731 None732 }733 })734 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;735 Ok(rs.len())736 })?;737 Ok(Some(T::WeightInfo::set_fee(registrars as u32)).into()) 738 }739740 741 742 743 744 745 746 747 748 749 750 751 752 753 #[pallet::call_index(7)]754 #[pallet::weight(T::WeightInfo::set_account_id(T::MaxRegistrars::get()))] 755 pub fn set_account_id(756 origin: OriginFor<T>,757 #[pallet::compact] index: RegistrarIndex,758 new: AccountIdLookupOf<T>,759 ) -> DispatchResultWithPostInfo {760 let who = ensure_signed(origin)?;761 let new = T::Lookup::lookup(new)?;762763 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {764 rs.get_mut(index as usize)765 .and_then(|x| x.as_mut())766 .and_then(|r| {767 if r.account == who {768 r.account = new;769 Some(())770 } else {771 None772 }773 })774 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;775 Ok(rs.len())776 })?;777 Ok(Some(T::WeightInfo::set_account_id(registrars as u32)).into()) 778 }779780 781 782 783 784 785 786 787 788 789 790 791 792 793 #[pallet::call_index(8)]794 #[pallet::weight(T::WeightInfo::set_fields(T::MaxRegistrars::get()))] 795 pub fn set_fields(796 origin: OriginFor<T>,797 #[pallet::compact] index: RegistrarIndex,798 fields: IdentityFields,799 ) -> DispatchResultWithPostInfo {800 let who = ensure_signed(origin)?;801802 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {803 rs.get_mut(index as usize)804 .and_then(|x| x.as_mut())805 .and_then(|r| {806 if r.account == who {807 r.fields = fields;808 Some(())809 } else {810 None811 }812 })813 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;814 Ok(rs.len())815 })?;816 Ok(Some(T::WeightInfo::set_fields(817 registrars as u32, 818 ))819 .into())820 }821822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 #[pallet::call_index(9)]843 #[pallet::weight(T::WeightInfo::provide_judgement(844 T::MaxRegistrars::get(), 845 T::MaxAdditionalFields::get(), 846 ))]847 pub fn provide_judgement(848 origin: OriginFor<T>,849 #[pallet::compact] reg_index: RegistrarIndex,850 target: AccountIdLookupOf<T>,851 judgement: Judgement<BalanceOf<T>>,852 identity: T::Hash,853 ) -> DispatchResultWithPostInfo {854 let sender = ensure_signed(origin)?;855 let target = T::Lookup::lookup(target)?;856 ensure!(!judgement.has_deposit(), Error::<T>::InvalidJudgement);857 <Registrars<T>>::get()858 .get(reg_index as usize)859 .and_then(Option::as_ref)860 .filter(|r| r.account == sender)861 .ok_or(Error::<T>::InvalidIndex)?;862 let mut id = <IdentityOf<T>>::get(&target).ok_or(Error::<T>::InvalidTarget)?;863864 if T::Hashing::hash_of(&id.info) != identity {865 return Err(Error::<T>::JudgementForDifferentIdentity.into());866 }867868 let item = (reg_index, judgement);869 match id.judgements.binary_search_by_key(®_index, |x| x.0) {870 Ok(position) => {871 if let Judgement::FeePaid(fee) = id.judgements[position].1 {872 T::Currency::repatriate_reserved(873 &target,874 &sender,875 fee,876 BalanceStatus::Free,877 )878 .map_err(|_| Error::<T>::JudgementPaymentFailed)?;879 }880 id.judgements[position] = item881 }882 Err(position) => id883 .judgements884 .try_insert(position, item)885 .map_err(|_| Error::<T>::TooManyRegistrars)?,886 }887888 let judgements = id.judgements.len();889 let extra_fields = id.info.additional.len();890 <IdentityOf<T>>::insert(&target, id);891 Self::deposit_event(Event::JudgementGiven {892 target,893 registrar_index: reg_index,894 });895896 Ok(Some(T::WeightInfo::provide_judgement(897 judgements as u32,898 extra_fields as u32,899 ))900 .into())901 }902903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 #[pallet::call_index(10)]923 #[pallet::weight(T::WeightInfo::kill_identity(924 T::MaxRegistrars::get(), 925 T::MaxSubAccounts::get(), 926 T::MaxAdditionalFields::get(), 927 ))]928 pub fn kill_identity(929 origin: OriginFor<T>,930 target: AccountIdLookupOf<T>,931 ) -> DispatchResultWithPostInfo {932 T::ForceOrigin::ensure_origin(origin)?;933934 935 let target = T::Lookup::lookup(target)?;936 937 let (subs_deposit, sub_ids) = <SubsOf<T>>::take(&target);938 let id = <IdentityOf<T>>::take(&target).ok_or(Error::<T>::NotNamed)?;939 let deposit = id.total_deposit() + subs_deposit;940 for sub in sub_ids.iter() {941 <SuperOf<T>>::remove(sub);942 }943 944 T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit).0);945946 Self::deposit_event(Event::IdentityKilled {947 who: target,948 deposit,949 });950951 Ok(Some(T::WeightInfo::kill_identity(952 id.judgements.len() as u32, 953 sub_ids.len() as u32, 954 id.info.additional.len() as u32, 955 ))956 .into())957 }958959 960 961 962 963 964 965 966 #[pallet::call_index(11)]967 #[pallet::weight(T::WeightInfo::add_sub(T::MaxSubAccounts::get()))]968 pub fn add_sub(969 origin: OriginFor<T>,970 sub: AccountIdLookupOf<T>,971 data: Data,972 ) -> DispatchResult {973 let sender = ensure_signed(origin)?;974 let sub = T::Lookup::lookup(sub)?;975 ensure!(976 IdentityOf::<T>::contains_key(&sender),977 Error::<T>::NoIdentity978 );979980 981 ensure!(982 !SuperOf::<T>::contains_key(&sub),983 Error::<T>::AlreadyClaimed984 );985986 SubsOf::<T>::try_mutate(&sender, |(ref mut subs_deposit, ref mut sub_ids)| {987 988 ensure!(989 sub_ids.len() < T::MaxSubAccounts::get() as usize,990 Error::<T>::TooManySubAccounts991 );992 let deposit = T::SubAccountDeposit::get();993 T::Currency::reserve(&sender, deposit)?;994995 SuperOf::<T>::insert(&sub, (sender.clone(), data));996 sub_ids997 .try_push(sub.clone())998 .expect("sub ids length checked above; qed");999 *subs_deposit = subs_deposit.saturating_add(deposit);10001001 Self::deposit_event(Event::SubIdentityAdded {1002 sub,1003 main: sender.clone(),1004 deposit,1005 });1006 Ok(())1007 })1008 }10091010 1011 1012 1013 1014 #[pallet::call_index(12)]1015 #[pallet::weight(T::WeightInfo::rename_sub(T::MaxSubAccounts::get()))]1016 pub fn rename_sub(1017 origin: OriginFor<T>,1018 sub: AccountIdLookupOf<T>,1019 data: Data,1020 ) -> DispatchResult {1021 let sender = ensure_signed(origin)?;1022 let sub = T::Lookup::lookup(sub)?;1023 ensure!(1024 IdentityOf::<T>::contains_key(&sender),1025 Error::<T>::NoIdentity1026 );1027 ensure!(1028 SuperOf::<T>::get(&sub).map_or(false, |x| x.0 == sender),1029 Error::<T>::NotOwned1030 );1031 SuperOf::<T>::insert(&sub, (sender, data));1032 Ok(())1033 }10341035 1036 1037 1038 1039 1040 1041 1042 #[pallet::call_index(13)]1043 #[pallet::weight(T::WeightInfo::remove_sub(T::MaxSubAccounts::get()))]1044 pub fn remove_sub(origin: OriginFor<T>, sub: AccountIdLookupOf<T>) -> DispatchResult {1045 let sender = ensure_signed(origin)?;1046 ensure!(1047 IdentityOf::<T>::contains_key(&sender),1048 Error::<T>::NoIdentity1049 );1050 let sub = T::Lookup::lookup(sub)?;1051 let (sup, _) = SuperOf::<T>::get(&sub).ok_or(Error::<T>::NotSub)?;1052 ensure!(sup == sender, Error::<T>::NotOwned);1053 SuperOf::<T>::remove(&sub);1054 SubsOf::<T>::mutate(&sup, |(ref mut subs_deposit, ref mut sub_ids)| {1055 sub_ids.retain(|x| x != &sub);1056 let deposit = T::SubAccountDeposit::get().min(*subs_deposit);1057 *subs_deposit -= deposit;1058 let err_amount = T::Currency::unreserve(&sender, deposit);1059 debug_assert!(err_amount.is_zero());1060 Self::deposit_event(Event::SubIdentityRemoved {1061 sub,1062 main: sender,1063 deposit,1064 });1065 });1066 Ok(())1067 }10681069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 #[pallet::call_index(14)]1080 #[pallet::weight(T::WeightInfo::quit_sub(T::MaxSubAccounts::get()))]1081 pub fn quit_sub(origin: OriginFor<T>) -> DispatchResult {1082 let sender = ensure_signed(origin)?;1083 let (sup, _) = SuperOf::<T>::take(&sender).ok_or(Error::<T>::NotSub)?;1084 SubsOf::<T>::mutate(&sup, |(ref mut subs_deposit, ref mut sub_ids)| {1085 sub_ids.retain(|x| x != &sender);1086 let deposit = T::SubAccountDeposit::get().min(*subs_deposit);1087 *subs_deposit -= deposit;1088 let _ =1089 T::Currency::repatriate_reserved(&sup, &sender, deposit, BalanceStatus::Free);1090 Self::deposit_event(Event::SubIdentityRevoked {1091 sub: sender,1092 main: sup.clone(),1093 deposit,1094 });1095 });1096 Ok(())1097 }10981099 1100 1101 1102 1103 1104 #[pallet::call_index(15)]1105 #[pallet::weight(T::WeightInfo::force_insert_identities(1106 T::MaxAdditionalFields::get(), 1107 identities.len() as u32, 1108 ))]1109 pub fn force_insert_identities(1110 origin: OriginFor<T>,1111 identities: Vec<(1112 T::AccountId,1113 Registration<BalanceOf<T>, T::MaxRegistrars, T::MaxAdditionalFields>,1114 )>,1115 ) -> DispatchResult {1116 T::ForceOrigin::ensure_origin(origin)?;1117 for identity in identities.clone() {1118 IdentityOf::<T>::insert(identity.0, identity.1);1119 }1120 Self::deposit_event(Event::IdentitiesInserted {1121 amount: identities.len() as u32,1122 });1123 Ok(())1124 }11251126 1127 1128 1129 1130 1131 #[pallet::call_index(16)]1132 #[pallet::weight(T::WeightInfo::force_remove_identities(1133 T::MaxAdditionalFields::get(), 1134 identities.len() as u32, 1135 ))]1136 pub fn force_remove_identities(1137 origin: OriginFor<T>,1138 identities: Vec<T::AccountId>,1139 ) -> DispatchResult {1140 T::ForceOrigin::ensure_origin(origin)?;1141 for identity in identities.clone() {1142 let (_, sub_ids) = <SubsOf<T>>::take(&identity);1143 <IdentityOf<T>>::remove(&identity);1144 for sub in sub_ids.iter() {1145 <SuperOf<T>>::remove(sub);1146 }1147 }1148 Self::deposit_event(Event::IdentitiesRemoved {1149 amount: identities.len() as u32,1150 });1151 Ok(())1152 }11531154 1155 1156 1157 1158 1159 #[pallet::call_index(17)]1160 #[pallet::weight(T::WeightInfo::force_set_subs(1161 T::MaxSubAccounts::get(), 1162 subs.len() as u32, 1163 ))]1164 pub fn force_set_subs(1165 origin: OriginFor<T>,1166 subs: Vec<(1167 T::AccountId,1168 (1169 BalanceOf<T>,1170 BoundedVec<(T::AccountId, Data), T::MaxSubAccounts>,1171 ),1172 )>,1173 ) -> DispatchResult {1174 T::ForceOrigin::ensure_origin(origin)?;1175 for identity in subs.clone() {1176 let account = identity.0;1177 let (_, old_subs) = <SubsOf<T>>::get(&account);1178 for old_sub in old_subs {1179 <SuperOf<T>>::remove(old_sub);1180 }11811182 let mut ids = BoundedVec::<T::AccountId, T::MaxSubAccounts>::default();1183 for (id, name) in identity.1 .1 {1184 <SuperOf<T>>::insert(&id, (account.clone(), name));1185 ids.try_push(id)1186 .expect("subs length is less than T::MaxSubAccounts; qed");1187 }11881189 if ids.is_empty() {1190 <SubsOf<T>>::remove(&account);1191 } else {1192 <SubsOf<T>>::insert(account, (identity.1 .0, ids));1193 }1194 }1195 Self::deposit_event(Event::SubIdentitiesInserted {1196 amount: subs.len() as u32,1197 });1198 Ok(())1199 }1200 }1201}12021203impl<T: Config> Pallet<T> {1204 1205 pub fn subs(who: &T::AccountId) -> Vec<(T::AccountId, Data)> {1206 SubsOf::<T>::get(who)1207 .11208 .into_iter()1209 .filter_map(|a| SuperOf::<T>::get(&a).map(|x| (a, x.1)))1210 .collect()1211 }12121213 1214 pub fn has_identity(who: &T::AccountId, fields: u64) -> bool {1215 IdentityOf::<T>::get(who).map_or(false, |registration| {1216 (registration.info.fields().0.bits() & fields) == fields1217 })1218 }1219}