123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990#![cfg_attr(not(feature = "std"), no_std)]9192mod benchmarking;93#[cfg(test)]94mod tests;95mod types;96pub mod weights;9798use frame_support::{99 traits::{BalanceStatus, Currency, OnUnbalanced, ReservableCurrency},100};101use sp_runtime::{102 BoundedVec,103 traits::{AppendZerosInput, Hash, Saturating, StaticLookup, Zero},104};105use sp_std::prelude::*;106pub use weights::WeightInfo;107108pub use pallet::*;109pub use types::{110 Data, IdentityField, IdentityFields, IdentityInfo, Judgement, RegistrarIndex, RegistrarInfo,111 Registration,112};113114pub type BalanceOf<T> =115 <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;116type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<117 <T as frame_system::Config>::AccountId,118>>::NegativeImbalance;119type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;120type RegistrarInfoOf<T> = RegistrarInfo<BalanceOf<T>, <T as frame_system::Config>::AccountId>;121type RegistrationOf<T> =122 Registration<BalanceOf<T>, <T as Config>::MaxRegistrars, <T as Config>::MaxAdditionalFields>;123type SubAccounts<T> =124 sp_runtime::BoundedVec<<T as frame_system::Config>::AccountId, <T as Config>::MaxSubAccounts>;125type SubAccountsByAccountId<T> = (126 <T as frame_system::Config>::AccountId,127 (128 BalanceOf<T>,129 BoundedVec<(<T as frame_system::Config>::AccountId, Data), <T as Config>::MaxSubAccounts>,130 ),131);132133#[frame_support::pallet]134pub mod pallet {135 use super::*;136 use frame_support::pallet_prelude::*;137 use frame_system::pallet_prelude::*;138139 #[pallet::config]140 pub trait Config: frame_system::Config {141 142 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;143144 145 type Currency: ReservableCurrency<Self::AccountId>;146147 148 #[pallet::constant]149 type BasicDeposit: Get<BalanceOf<Self>>;150151 152 #[pallet::constant]153 type FieldDeposit: Get<BalanceOf<Self>>;154155 156 157 158 #[pallet::constant]159 type SubAccountDeposit: Get<BalanceOf<Self>>;160161 162 #[pallet::constant]163 type MaxSubAccounts: Get<u32>;164165 166 167 #[pallet::constant]168 type MaxAdditionalFields: Get<u32>;169170 171 172 #[pallet::constant]173 type MaxRegistrars: Get<u32>;174175 176 type Slashed: OnUnbalanced<NegativeImbalanceOf<Self>>;177178 179 type ForceOrigin: EnsureOrigin<Self::RuntimeOrigin>;180181 182 type RegistrarOrigin: EnsureOrigin<Self::RuntimeOrigin>;183184 185 type WeightInfo: WeightInfo;186 }187188 #[pallet::pallet]189 pub struct Pallet<T>(_);190191 192 193 194 #[pallet::storage]195 #[pallet::getter(fn identity)]196 pub(super) type IdentityOf<T: Config> = StorageMap<197 _,198 Twox64Concat,199 T::AccountId,200 Registration<BalanceOf<T>, T::MaxRegistrars, T::MaxAdditionalFields>,201 OptionQuery,202 >;203204 205 206 #[pallet::storage]207 #[pallet::getter(fn super_of)]208 pub(super) type SuperOf<T: Config> =209 StorageMap<_, Blake2_128Concat, T::AccountId, (T::AccountId, Data), OptionQuery>;210211 212 213 214 215 216 #[pallet::storage]217 #[pallet::getter(fn subs_of)]218 pub(super) type SubsOf<T: Config> =219 StorageMap<_, Twox64Concat, T::AccountId, (BalanceOf<T>, SubAccounts<T>), ValueQuery>;220221 222 223 224 225 #[pallet::storage]226 #[pallet::getter(fn registrars)]227 pub(super) type Registrars<T: Config> =228 StorageValue<_, BoundedVec<Option<RegistrarInfoOf<T>>, T::MaxRegistrars>, ValueQuery>;229230 #[pallet::error]231 pub enum Error<T> {232 233 TooManySubAccounts,234 235 NotFound,236 237 NotNamed,238 239 EmptyIndex,240 241 FeeChanged,242 243 NoIdentity,244 245 StickyJudgement,246 247 JudgementGiven,248 249 InvalidJudgement,250 251 InvalidIndex,252 253 InvalidTarget,254 255 TooManyFields,256 257 TooManyRegistrars,258 259 AlreadyClaimed,260 261 NotSub,262 263 NotOwned,264 265 JudgementForDifferentIdentity,266 267 JudgementPaymentFailed,268 }269270 #[pallet::event]271 #[pallet::generate_deposit(pub(super) fn deposit_event)]272 pub enum Event<T: Config> {273 274 IdentitySet { who: T::AccountId },275 276 IdentityCleared {277 who: T::AccountId,278 deposit: BalanceOf<T>,279 },280 281 IdentityKilled {282 who: T::AccountId,283 deposit: BalanceOf<T>,284 },285 286 IdentitiesInserted { amount: u32 },287 288 IdentitiesRemoved { amount: u32 },289 290 JudgementRequested {291 who: T::AccountId,292 registrar_index: RegistrarIndex,293 },294 295 JudgementUnrequested {296 who: T::AccountId,297 registrar_index: RegistrarIndex,298 },299 300 JudgementGiven {301 target: T::AccountId,302 registrar_index: RegistrarIndex,303 },304 305 RegistrarAdded { registrar_index: RegistrarIndex },306 307 SubIdentityAdded {308 sub: T::AccountId,309 main: T::AccountId,310 deposit: BalanceOf<T>,311 },312 313 SubIdentityRemoved {314 sub: T::AccountId,315 main: T::AccountId,316 deposit: BalanceOf<T>,317 },318 319 320 SubIdentityRevoked {321 sub: T::AccountId,322 main: T::AccountId,323 deposit: BalanceOf<T>,324 },325 326 SubIdentitiesInserted { amount: u32 },327 }328329 #[pallet::call]330 331 impl<T: Config> Pallet<T> {332 333 334 335 336 337 338 339 340 341 342 343 344 345 #[pallet::call_index(0)]346 #[pallet::weight(T::WeightInfo::add_registrar(T::MaxRegistrars::get()))]347 pub fn add_registrar(348 origin: OriginFor<T>,349 account: AccountIdLookupOf<T>,350 ) -> DispatchResultWithPostInfo {351 T::RegistrarOrigin::ensure_origin(origin)?;352 let account = T::Lookup::lookup(account)?;353354 let (i, registrar_count) = <Registrars<T>>::try_mutate(355 |registrars| -> Result<(RegistrarIndex, usize), DispatchError> {356 registrars357 .try_push(Some(RegistrarInfo {358 account,359 fee: Zero::zero(),360 fields: Default::default(),361 }))362 .map_err(|_| Error::<T>::TooManyRegistrars)?;363 Ok(((registrars.len() - 1) as RegistrarIndex, registrars.len()))364 },365 )?;366367 Self::deposit_event(Event::RegistrarAdded { registrar_index: i });368369 Ok(Some(T::WeightInfo::add_registrar(registrar_count as u32)).into())370 }371372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 #[pallet::call_index(1)]392 #[pallet::weight( T::WeightInfo::set_identity(393 T::MaxRegistrars::get(), 394 T::MaxAdditionalFields::get(), 395 ))]396 pub fn set_identity(397 origin: OriginFor<T>,398 info: Box<IdentityInfo<T::MaxAdditionalFields>>,399 ) -> DispatchResultWithPostInfo {400 let sender = ensure_signed(origin)?;401 let extra_fields = info.additional.len() as u32;402 ensure!(403 extra_fields <= T::MaxAdditionalFields::get(),404 Error::<T>::TooManyFields405 );406 let fd = <BalanceOf<T>>::from(extra_fields) * T::FieldDeposit::get();407408 let mut id = match <IdentityOf<T>>::get(&sender) {409 Some(mut id) => {410 411 id.judgements.retain(|j| j.1.is_sticky());412 id.info = *info;413 id414 }415 None => Registration {416 info: *info,417 judgements: BoundedVec::default(),418 deposit: Zero::zero(),419 },420 };421422 let old_deposit = id.deposit;423 id.deposit = T::BasicDeposit::get() + fd;424 if id.deposit > old_deposit {425 T::Currency::reserve(&sender, id.deposit - old_deposit)?;426 }427 if old_deposit > id.deposit {428 let err_amount = T::Currency::unreserve(&sender, old_deposit - id.deposit);429 debug_assert!(err_amount.is_zero());430 }431432 let judgements = id.judgements.len();433 <IdentityOf<T>>::insert(&sender, id);434 Self::deposit_event(Event::IdentitySet { who: sender });435436 Ok(Some(T::WeightInfo::set_identity(437 judgements as u32, 438 extra_fields, 439 ))440 .into())441 }442443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 #[pallet::call_index(2)]471 #[pallet::weight(T::WeightInfo::set_subs_old(T::MaxSubAccounts::get()) 472 .saturating_add(T::WeightInfo::set_subs_new(subs.len() as u32)) 473 )]474 pub fn set_subs(475 origin: OriginFor<T>,476 subs: Vec<(T::AccountId, Data)>,477 ) -> DispatchResultWithPostInfo {478 let sender = ensure_signed(origin)?;479 ensure!(<IdentityOf<T>>::contains_key(&sender), Error::<T>::NotFound);480 ensure!(481 subs.len() <= T::MaxSubAccounts::get() as usize,482 Error::<T>::TooManySubAccounts483 );484485 let (old_deposit, old_ids) = <SubsOf<T>>::get(&sender);486 let new_deposit = T::SubAccountDeposit::get() * <BalanceOf<T>>::from(subs.len() as u32);487488 let not_other_sub = subs489 .iter()490 .filter_map(|i| SuperOf::<T>::get(&i.0))491 .all(|i| i.0 == sender);492 ensure!(not_other_sub, Error::<T>::AlreadyClaimed);493494 match old_deposit.cmp(&new_deposit) {495 core::cmp::Ordering::Less => {496 T::Currency::reserve(&sender, new_deposit - old_deposit)?497 }498 core::cmp::Ordering::Equal => { }499 core::cmp::Ordering::Greater => {500 let err_amount = T::Currency::unreserve(&sender, old_deposit - new_deposit);501 debug_assert!(err_amount.is_zero());502 }503 }504505 for s in old_ids.iter() {506 <SuperOf<T>>::remove(s);507 }508 let mut ids = <SubAccounts<T>>::default();509 for (id, name) in subs {510 <SuperOf<T>>::insert(&id, (sender.clone(), name));511 ids.try_push(id)512 .expect("subs length is less than T::MaxSubAccounts; qed");513 }514 let new_subs = ids.len();515516 if ids.is_empty() {517 <SubsOf<T>>::remove(&sender);518 } else {519 <SubsOf<T>>::insert(&sender, (new_deposit, ids));520 }521522 Ok(Some(523 T::WeightInfo::set_subs_old(old_ids.len() as u32) 524 525 .saturating_add(T::WeightInfo::set_subs_new(new_subs as u32)),526 )527 .into())528 }529530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 #[pallet::call_index(3)]549 #[pallet::weight(T::WeightInfo::clear_identity(550 T::MaxRegistrars::get(), 551 T::MaxSubAccounts::get(), 552 T::MaxAdditionalFields::get(), 553 ))]554 pub fn clear_identity(origin: OriginFor<T>) -> DispatchResultWithPostInfo {555 let sender = ensure_signed(origin)?;556557 let (subs_deposit, sub_ids) = <SubsOf<T>>::take(&sender);558 let id = <IdentityOf<T>>::take(&sender).ok_or(Error::<T>::NotNamed)?;559 let deposit = id.total_deposit() + subs_deposit;560 for sub in sub_ids.iter() {561 <SuperOf<T>>::remove(sub);562 }563564 let err_amount = T::Currency::unreserve(&sender, deposit);565 debug_assert!(err_amount.is_zero());566567 Self::deposit_event(Event::IdentityCleared {568 who: sender,569 deposit,570 });571572 Ok(Some(T::WeightInfo::clear_identity(573 id.judgements.len() as u32, 574 sub_ids.len() as u32, 575 id.info.additional.len() as u32, 576 ))577 .into())578 }579580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 #[pallet::call_index(4)]604 #[pallet::weight(T::WeightInfo::request_judgement(605 T::MaxRegistrars::get(), 606 T::MaxAdditionalFields::get(), 607 ))]608 pub fn request_judgement(609 origin: OriginFor<T>,610 #[pallet::compact] reg_index: RegistrarIndex,611 #[pallet::compact] max_fee: BalanceOf<T>,612 ) -> DispatchResultWithPostInfo {613 let sender = ensure_signed(origin)?;614 let registrars = <Registrars<T>>::get();615 let registrar = registrars616 .get(reg_index as usize)617 .and_then(Option::as_ref)618 .ok_or(Error::<T>::EmptyIndex)?;619 ensure!(max_fee >= registrar.fee, Error::<T>::FeeChanged);620 let mut id = <IdentityOf<T>>::get(&sender).ok_or(Error::<T>::NoIdentity)?;621622 let item = (reg_index, Judgement::FeePaid(registrar.fee));623 match id.judgements.binary_search_by_key(®_index, |x| x.0) {624 Ok(i) => {625 if id.judgements[i].1.is_sticky() {626 return Err(Error::<T>::StickyJudgement.into());627 } else {628 id.judgements[i] = item629 }630 }631 Err(i) => id632 .judgements633 .try_insert(i, item)634 .map_err(|_| Error::<T>::TooManyRegistrars)?,635 }636637 T::Currency::reserve(&sender, registrar.fee)?;638639 let judgements = id.judgements.len();640 let extra_fields = id.info.additional.len();641 <IdentityOf<T>>::insert(&sender, id);642643 Self::deposit_event(Event::JudgementRequested {644 who: sender,645 registrar_index: reg_index,646 });647648 Ok(Some(T::WeightInfo::request_judgement(649 judgements as u32,650 extra_fields as u32,651 ))652 .into())653 }654655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 #[pallet::call_index(5)]673 #[pallet::weight(T::WeightInfo::cancel_request(674 T::MaxRegistrars::get(), 675 T::MaxAdditionalFields::get(), 676 ))]677 pub fn cancel_request(678 origin: OriginFor<T>,679 reg_index: RegistrarIndex,680 ) -> DispatchResultWithPostInfo {681 let sender = ensure_signed(origin)?;682 let mut id = <IdentityOf<T>>::get(&sender).ok_or(Error::<T>::NoIdentity)?;683684 let pos = id685 .judgements686 .binary_search_by_key(®_index, |x| x.0)687 .map_err(|_| Error::<T>::NotFound)?;688 let fee = if let Judgement::FeePaid(fee) = id.judgements.remove(pos).1 {689 fee690 } else {691 return Err(Error::<T>::JudgementGiven.into());692 };693694 let err_amount = T::Currency::unreserve(&sender, fee);695 debug_assert!(err_amount.is_zero());696 let judgements = id.judgements.len();697 let extra_fields = id.info.additional.len();698 <IdentityOf<T>>::insert(&sender, id);699700 Self::deposit_event(Event::JudgementUnrequested {701 who: sender,702 registrar_index: reg_index,703 });704705 Ok(Some(T::WeightInfo::cancel_request(706 judgements as u32,707 extra_fields as u32,708 ))709 .into())710 }711712 713 714 715 716 717 718 719 720 721 722 723 724 725 #[pallet::call_index(6)]726 #[pallet::weight(T::WeightInfo::set_fee(T::MaxRegistrars::get()))] 727 pub fn set_fee(728 origin: OriginFor<T>,729 #[pallet::compact] index: RegistrarIndex,730 #[pallet::compact] fee: BalanceOf<T>,731 ) -> DispatchResultWithPostInfo {732 let who = ensure_signed(origin)?;733734 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {735 rs.get_mut(index as usize)736 .and_then(|x| x.as_mut())737 .and_then(|r| {738 if r.account == who {739 r.fee = fee;740 Some(())741 } else {742 None743 }744 })745 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;746 Ok(rs.len())747 })?;748 Ok(Some(T::WeightInfo::set_fee(registrars as u32)).into()) 749 }750751 752 753 754 755 756 757 758 759 760 761 762 763 764 #[pallet::call_index(7)]765 #[pallet::weight(T::WeightInfo::set_account_id(T::MaxRegistrars::get()))] 766 pub fn set_account_id(767 origin: OriginFor<T>,768 #[pallet::compact] index: RegistrarIndex,769 new: AccountIdLookupOf<T>,770 ) -> DispatchResultWithPostInfo {771 let who = ensure_signed(origin)?;772 let new = T::Lookup::lookup(new)?;773774 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {775 rs.get_mut(index as usize)776 .and_then(|x| x.as_mut())777 .and_then(|r| {778 if r.account == who {779 r.account = new;780 Some(())781 } else {782 None783 }784 })785 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;786 Ok(rs.len())787 })?;788 Ok(Some(T::WeightInfo::set_account_id(registrars as u32)).into()) 789 }790791 792 793 794 795 796 797 798 799 800 801 802 803 804 #[pallet::call_index(8)]805 #[pallet::weight(T::WeightInfo::set_fields(T::MaxRegistrars::get()))] 806 pub fn set_fields(807 origin: OriginFor<T>,808 #[pallet::compact] index: RegistrarIndex,809 fields: IdentityFields,810 ) -> DispatchResultWithPostInfo {811 let who = ensure_signed(origin)?;812813 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {814 rs.get_mut(index as usize)815 .and_then(|x| x.as_mut())816 .and_then(|r| {817 if r.account == who {818 r.fields = fields;819 Some(())820 } else {821 None822 }823 })824 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;825 Ok(rs.len())826 })?;827 Ok(Some(T::WeightInfo::set_fields(828 registrars as u32, 829 ))830 .into())831 }832833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 #[pallet::call_index(9)]854 #[pallet::weight(T::WeightInfo::provide_judgement(855 T::MaxRegistrars::get(), 856 T::MaxAdditionalFields::get(), 857 ))]858 pub fn provide_judgement(859 origin: OriginFor<T>,860 #[pallet::compact] reg_index: RegistrarIndex,861 target: AccountIdLookupOf<T>,862 judgement: Judgement<BalanceOf<T>>,863 identity: T::Hash,864 ) -> DispatchResultWithPostInfo {865 let sender = ensure_signed(origin)?;866 let target = T::Lookup::lookup(target)?;867 ensure!(!judgement.has_deposit(), Error::<T>::InvalidJudgement);868 <Registrars<T>>::get()869 .get(reg_index as usize)870 .and_then(Option::as_ref)871 .filter(|r| r.account == sender)872 .ok_or(Error::<T>::InvalidIndex)?;873 let mut id = <IdentityOf<T>>::get(&target).ok_or(Error::<T>::InvalidTarget)?;874875 if T::Hashing::hash_of(&id.info) != identity {876 return Err(Error::<T>::JudgementForDifferentIdentity.into());877 }878879 let item = (reg_index, judgement);880 match id.judgements.binary_search_by_key(®_index, |x| x.0) {881 Ok(position) => {882 if let Judgement::FeePaid(fee) = id.judgements[position].1 {883 T::Currency::repatriate_reserved(884 &target,885 &sender,886 fee,887 BalanceStatus::Free,888 )889 .map_err(|_| Error::<T>::JudgementPaymentFailed)?;890 }891 id.judgements[position] = item892 }893 Err(position) => id894 .judgements895 .try_insert(position, item)896 .map_err(|_| Error::<T>::TooManyRegistrars)?,897 }898899 let judgements = id.judgements.len();900 let extra_fields = id.info.additional.len();901 <IdentityOf<T>>::insert(&target, id);902 Self::deposit_event(Event::JudgementGiven {903 target,904 registrar_index: reg_index,905 });906907 Ok(Some(T::WeightInfo::provide_judgement(908 judgements as u32,909 extra_fields as u32,910 ))911 .into())912 }913914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 #[pallet::call_index(10)]934 #[pallet::weight(T::WeightInfo::kill_identity(935 T::MaxRegistrars::get(), 936 T::MaxSubAccounts::get(), 937 T::MaxAdditionalFields::get(), 938 ))]939 pub fn kill_identity(940 origin: OriginFor<T>,941 target: AccountIdLookupOf<T>,942 ) -> DispatchResultWithPostInfo {943 T::ForceOrigin::ensure_origin(origin)?;944945 946 let target = T::Lookup::lookup(target)?;947 948 let (subs_deposit, sub_ids) = <SubsOf<T>>::take(&target);949 let id = <IdentityOf<T>>::take(&target).ok_or(Error::<T>::NotNamed)?;950 let deposit = id.total_deposit() + subs_deposit;951 for sub in sub_ids.iter() {952 <SuperOf<T>>::remove(sub);953 }954 955 T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit).0);956957 Self::deposit_event(Event::IdentityKilled {958 who: target,959 deposit,960 });961962 Ok(Some(T::WeightInfo::kill_identity(963 id.judgements.len() as u32, 964 sub_ids.len() as u32, 965 id.info.additional.len() as u32, 966 ))967 .into())968 }969970 971 972 973 974 975 976 977 #[pallet::call_index(11)]978 #[pallet::weight(T::WeightInfo::add_sub(T::MaxSubAccounts::get()))]979 pub fn add_sub(980 origin: OriginFor<T>,981 sub: AccountIdLookupOf<T>,982 data: Data,983 ) -> DispatchResult {984 let sender = ensure_signed(origin)?;985 let sub = T::Lookup::lookup(sub)?;986 ensure!(987 IdentityOf::<T>::contains_key(&sender),988 Error::<T>::NoIdentity989 );990991 992 ensure!(993 !SuperOf::<T>::contains_key(&sub),994 Error::<T>::AlreadyClaimed995 );996997 SubsOf::<T>::try_mutate(&sender, |(ref mut subs_deposit, ref mut sub_ids)| {998 999 ensure!(1000 sub_ids.len() < T::MaxSubAccounts::get() as usize,1001 Error::<T>::TooManySubAccounts1002 );1003 let deposit = T::SubAccountDeposit::get();1004 T::Currency::reserve(&sender, deposit)?;10051006 SuperOf::<T>::insert(&sub, (sender.clone(), data));1007 sub_ids1008 .try_push(sub.clone())1009 .expect("sub ids length checked above; qed");1010 *subs_deposit = subs_deposit.saturating_add(deposit);10111012 Self::deposit_event(Event::SubIdentityAdded {1013 sub,1014 main: sender.clone(),1015 deposit,1016 });1017 Ok(())1018 })1019 }10201021 1022 1023 1024 1025 #[pallet::call_index(12)]1026 #[pallet::weight(T::WeightInfo::rename_sub(T::MaxSubAccounts::get()))]1027 pub fn rename_sub(1028 origin: OriginFor<T>,1029 sub: AccountIdLookupOf<T>,1030 data: Data,1031 ) -> DispatchResult {1032 let sender = ensure_signed(origin)?;1033 let sub = T::Lookup::lookup(sub)?;1034 ensure!(1035 IdentityOf::<T>::contains_key(&sender),1036 Error::<T>::NoIdentity1037 );1038 ensure!(1039 SuperOf::<T>::get(&sub).map_or(false, |x| x.0 == sender),1040 Error::<T>::NotOwned1041 );1042 SuperOf::<T>::insert(&sub, (sender, data));1043 Ok(())1044 }10451046 1047 1048 1049 1050 1051 1052 1053 #[pallet::call_index(13)]1054 #[pallet::weight(T::WeightInfo::remove_sub(T::MaxSubAccounts::get()))]1055 pub fn remove_sub(origin: OriginFor<T>, sub: AccountIdLookupOf<T>) -> DispatchResult {1056 let sender = ensure_signed(origin)?;1057 ensure!(1058 IdentityOf::<T>::contains_key(&sender),1059 Error::<T>::NoIdentity1060 );1061 let sub = T::Lookup::lookup(sub)?;1062 let (sup, _) = SuperOf::<T>::get(&sub).ok_or(Error::<T>::NotSub)?;1063 ensure!(sup == sender, Error::<T>::NotOwned);1064 SuperOf::<T>::remove(&sub);1065 SubsOf::<T>::mutate(&sup, |(ref mut subs_deposit, ref mut sub_ids)| {1066 sub_ids.retain(|x| x != &sub);1067 let deposit = T::SubAccountDeposit::get().min(*subs_deposit);1068 *subs_deposit -= deposit;1069 let err_amount = T::Currency::unreserve(&sender, deposit);1070 debug_assert!(err_amount.is_zero());1071 Self::deposit_event(Event::SubIdentityRemoved {1072 sub,1073 main: sender,1074 deposit,1075 });1076 });1077 Ok(())1078 }10791080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 #[pallet::call_index(14)]1091 #[pallet::weight(T::WeightInfo::quit_sub(T::MaxSubAccounts::get()))]1092 pub fn quit_sub(origin: OriginFor<T>) -> DispatchResult {1093 let sender = ensure_signed(origin)?;1094 let (sup, _) = SuperOf::<T>::take(&sender).ok_or(Error::<T>::NotSub)?;1095 SubsOf::<T>::mutate(&sup, |(ref mut subs_deposit, ref mut sub_ids)| {1096 sub_ids.retain(|x| x != &sender);1097 let deposit = T::SubAccountDeposit::get().min(*subs_deposit);1098 *subs_deposit -= deposit;1099 let _ =1100 T::Currency::repatriate_reserved(&sup, &sender, deposit, BalanceStatus::Free);1101 Self::deposit_event(Event::SubIdentityRevoked {1102 sub: sender,1103 main: sup.clone(),1104 deposit,1105 });1106 });1107 Ok(())1108 }11091110 1111 1112 1113 1114 1115 #[pallet::call_index(15)]1116 #[pallet::weight(T::WeightInfo::force_insert_identities(1117 T::MaxAdditionalFields::get(), 1118 identities.len() as u32, 1119 ))]1120 pub fn force_insert_identities(1121 origin: OriginFor<T>,1122 identities: Vec<(T::AccountId, RegistrationOf<T>)>,1123 ) -> DispatchResult {1124 T::ForceOrigin::ensure_origin(origin)?;1125 for identity in identities.clone() {1126 IdentityOf::<T>::insert(identity.0, identity.1);1127 }1128 Self::deposit_event(Event::IdentitiesInserted {1129 amount: identities.len() as u32,1130 });1131 Ok(())1132 }11331134 1135 1136 1137 1138 1139 #[pallet::call_index(16)]1140 #[pallet::weight(T::WeightInfo::force_remove_identities(1141 T::MaxAdditionalFields::get(), 1142 identities.len() as u32, 1143 ))]1144 pub fn force_remove_identities(1145 origin: OriginFor<T>,1146 identities: Vec<T::AccountId>,1147 ) -> DispatchResult {1148 T::ForceOrigin::ensure_origin(origin)?;1149 for identity in identities.clone() {1150 let (_, sub_ids) = <SubsOf<T>>::take(&identity);1151 <IdentityOf<T>>::remove(&identity);1152 for sub in sub_ids.iter() {1153 <SuperOf<T>>::remove(sub);1154 }1155 }1156 Self::deposit_event(Event::IdentitiesRemoved {1157 amount: identities.len() as u32,1158 });1159 Ok(())1160 }11611162 1163 1164 1165 1166 1167 #[pallet::call_index(17)]1168 #[pallet::weight(T::WeightInfo::force_set_subs(1169 T::MaxSubAccounts::get(), 1170 subs.len() as u32, 1171 ))]1172 pub fn force_set_subs(1173 origin: OriginFor<T>,1174 subs: Vec<SubAccountsByAccountId<T>>,1175 ) -> DispatchResult {1176 T::ForceOrigin::ensure_origin(origin)?;1177 for identity in subs.clone() {1178 let account = identity.0;1179 let (_, old_subs) = <SubsOf<T>>::get(&account);1180 for old_sub in old_subs {1181 <SuperOf<T>>::remove(old_sub);1182 }11831184 let mut ids = <SubAccounts<T>>::default();1185 for (id, name) in identity.1 .1 {1186 <SuperOf<T>>::insert(&id, (account.clone(), name));1187 ids.try_push(id)1188 .expect("subs length is less than T::MaxSubAccounts; qed");1189 }11901191 if ids.is_empty() {1192 <SubsOf<T>>::remove(&account);1193 } else {1194 <SubsOf<T>>::insert(account, (identity.1 .0, ids));1195 }1196 }1197 Self::deposit_event(Event::SubIdentitiesInserted {1198 amount: subs.len() as u32,1199 });1200 Ok(())1201 }1202 }1203}12041205impl<T: Config> Pallet<T> {1206 1207 pub fn subs(who: &T::AccountId) -> Vec<(T::AccountId, Data)> {1208 SubsOf::<T>::get(who)1209 .11210 .into_iter()1211 .filter_map(|a| SuperOf::<T>::get(&a).map(|x| (a, x.1)))1212 .collect()1213 }12141215 1216 pub fn has_identity(who: &T::AccountId, fields: u64) -> bool {1217 IdentityOf::<T>::get(who).map_or(false, |registration| {1218 (registration.info.fields().0.bits() & fields) == fields1219 })1220 }1221}