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};99pub use pallet::*;100use sp_runtime::{101 traits::{AppendZerosInput, Hash, Saturating, StaticLookup, Zero},102 BoundedVec,103};104use sp_std::prelude::*;105pub use types::{106 Data, IdentityField, IdentityFields, IdentityInfo, Judgement, RegistrarIndex, RegistrarInfo,107 Registration,108};109pub use weights::WeightInfo;110111pub type BalanceOf<T> =112 <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;113type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<114 <T as frame_system::Config>::AccountId,115>>::NegativeImbalance;116type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;117type RegistrarInfoOf<T> = RegistrarInfo<BalanceOf<T>, <T as frame_system::Config>::AccountId>;118type RegistrationOf<T> =119 Registration<BalanceOf<T>, <T as Config>::MaxRegistrars, <T as Config>::MaxAdditionalFields>;120type SubAccounts<T> =121 sp_runtime::BoundedVec<<T as frame_system::Config>::AccountId, <T as Config>::MaxSubAccounts>;122type SubAccountsByAccountId<T> = (123 <T as frame_system::Config>::AccountId,124 (125 BalanceOf<T>,126 BoundedVec<(<T as frame_system::Config>::AccountId, Data), <T as Config>::MaxSubAccounts>,127 ),128);129130#[frame_support::pallet]131pub mod pallet {132 use frame_support::pallet_prelude::*;133 use frame_system::pallet_prelude::*;134135 use super::*;136137 #[pallet::config]138 pub trait Config: frame_system::Config {139 140 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;141142 143 type Currency: ReservableCurrency<Self::AccountId>;144145 146 #[pallet::constant]147 type BasicDeposit: Get<BalanceOf<Self>>;148149 150 #[pallet::constant]151 type FieldDeposit: Get<BalanceOf<Self>>;152153 154 155 156 #[pallet::constant]157 type SubAccountDeposit: Get<BalanceOf<Self>>;158159 160 #[pallet::constant]161 type MaxSubAccounts: Get<u32>;162163 164 165 #[pallet::constant]166 type MaxAdditionalFields: Get<u32>;167168 169 170 #[pallet::constant]171 type MaxRegistrars: Get<u32>;172173 174 type Slashed: OnUnbalanced<NegativeImbalanceOf<Self>>;175176 177 type ForceOrigin: EnsureOrigin<Self::RuntimeOrigin>;178179 180 type RegistrarOrigin: EnsureOrigin<Self::RuntimeOrigin>;181182 183 type WeightInfo: WeightInfo;184 }185186 #[pallet::pallet]187 pub struct Pallet<T>(_);188189 190 191 192 #[pallet::storage]193 #[pallet::getter(fn identity)]194 pub(super) type IdentityOf<T: Config> = StorageMap<195 _,196 Twox64Concat,197 T::AccountId,198 Registration<BalanceOf<T>, T::MaxRegistrars, T::MaxAdditionalFields>,199 OptionQuery,200 >;201202 203 204 #[pallet::storage]205 #[pallet::getter(fn super_of)]206 pub(super) type SuperOf<T: Config> =207 StorageMap<_, Blake2_128Concat, T::AccountId, (T::AccountId, Data), OptionQuery>;208209 210 211 212 213 214 #[pallet::storage]215 #[pallet::getter(fn subs_of)]216 pub(super) type SubsOf<T: Config> =217 StorageMap<_, Twox64Concat, T::AccountId, (BalanceOf<T>, SubAccounts<T>), ValueQuery>;218219 220 221 222 223 #[pallet::storage]224 #[pallet::getter(fn registrars)]225 pub(super) type Registrars<T: Config> =226 StorageValue<_, BoundedVec<Option<RegistrarInfoOf<T>>, T::MaxRegistrars>, ValueQuery>;227228 #[pallet::error]229 pub enum Error<T> {230 231 TooManySubAccounts,232 233 NotFound,234 235 NotNamed,236 237 EmptyIndex,238 239 FeeChanged,240 241 NoIdentity,242 243 StickyJudgement,244 245 JudgementGiven,246 247 InvalidJudgement,248 249 InvalidIndex,250 251 InvalidTarget,252 253 TooManyFields,254 255 TooManyRegistrars,256 257 AlreadyClaimed,258 259 NotSub,260 261 NotOwned,262 263 JudgementForDifferentIdentity,264 265 JudgementPaymentFailed,266 }267268 #[pallet::event]269 #[pallet::generate_deposit(pub(super) fn deposit_event)]270 pub enum Event<T: Config> {271 272 IdentitySet { who: T::AccountId },273 274 IdentityCleared {275 who: T::AccountId,276 deposit: BalanceOf<T>,277 },278 279 IdentityKilled {280 who: T::AccountId,281 deposit: BalanceOf<T>,282 },283 284 IdentitiesInserted { amount: u32 },285 286 IdentitiesRemoved { amount: u32 },287 288 JudgementRequested {289 who: T::AccountId,290 registrar_index: RegistrarIndex,291 },292 293 JudgementUnrequested {294 who: T::AccountId,295 registrar_index: RegistrarIndex,296 },297 298 JudgementGiven {299 target: T::AccountId,300 registrar_index: RegistrarIndex,301 },302 303 RegistrarAdded { registrar_index: RegistrarIndex },304 305 SubIdentityAdded {306 sub: T::AccountId,307 main: T::AccountId,308 deposit: BalanceOf<T>,309 },310 311 SubIdentityRemoved {312 sub: T::AccountId,313 main: T::AccountId,314 deposit: BalanceOf<T>,315 },316 317 318 SubIdentityRevoked {319 sub: T::AccountId,320 main: T::AccountId,321 deposit: BalanceOf<T>,322 },323 324 SubIdentitiesInserted { amount: u32 },325 }326327 #[pallet::call]328 329 impl<T: Config> Pallet<T> {330 331 332 333 334 335 336 337 338 339 340 341 342 343 #[pallet::call_index(0)]344 #[pallet::weight(T::WeightInfo::add_registrar(T::MaxRegistrars::get()))]345 pub fn add_registrar(346 origin: OriginFor<T>,347 account: AccountIdLookupOf<T>,348 ) -> DispatchResultWithPostInfo {349 T::RegistrarOrigin::ensure_origin(origin)?;350 let account = T::Lookup::lookup(account)?;351352 let (i, registrar_count) = <Registrars<T>>::try_mutate(353 |registrars| -> Result<(RegistrarIndex, usize), DispatchError> {354 registrars355 .try_push(Some(RegistrarInfo {356 account,357 fee: Zero::zero(),358 fields: Default::default(),359 }))360 .map_err(|_| Error::<T>::TooManyRegistrars)?;361 Ok(((registrars.len() - 1) as RegistrarIndex, registrars.len()))362 },363 )?;364365 Self::deposit_event(Event::RegistrarAdded { registrar_index: i });366367 Ok(Some(T::WeightInfo::add_registrar(registrar_count as u32)).into())368 }369370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 #[pallet::call_index(1)]390 #[pallet::weight( T::WeightInfo::set_identity(391 T::MaxRegistrars::get(), 392 T::MaxAdditionalFields::get(), 393 ))]394 pub fn set_identity(395 origin: OriginFor<T>,396 info: Box<IdentityInfo<T::MaxAdditionalFields>>,397 ) -> DispatchResultWithPostInfo {398 let sender = ensure_signed(origin)?;399 let extra_fields = info.additional.len() as u32;400 ensure!(401 extra_fields <= T::MaxAdditionalFields::get(),402 Error::<T>::TooManyFields403 );404 let fd = <BalanceOf<T>>::from(extra_fields) * T::FieldDeposit::get();405406 let mut id = match <IdentityOf<T>>::get(&sender) {407 Some(mut id) => {408 409 id.judgements.retain(|j| j.1.is_sticky());410 id.info = *info;411 id412 }413 None => Registration {414 info: *info,415 judgements: BoundedVec::default(),416 deposit: Zero::zero(),417 },418 };419420 let old_deposit = id.deposit;421 id.deposit = T::BasicDeposit::get() + fd;422 if id.deposit > old_deposit {423 T::Currency::reserve(&sender, id.deposit - old_deposit)?;424 }425 if old_deposit > id.deposit {426 let err_amount = T::Currency::unreserve(&sender, old_deposit - id.deposit);427 debug_assert!(err_amount.is_zero());428 }429430 let judgements = id.judgements.len();431 <IdentityOf<T>>::insert(&sender, id);432 Self::deposit_event(Event::IdentitySet { who: sender });433434 Ok(Some(T::WeightInfo::set_identity(435 judgements as u32, 436 extra_fields, 437 ))438 .into())439 }440441 442 443 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 #[pallet::call_index(2)]469 #[pallet::weight(T::WeightInfo::set_subs_old(T::MaxSubAccounts::get()) 470 .saturating_add(T::WeightInfo::set_subs_new(subs.len() as u32)) 471 )]472 pub fn set_subs(473 origin: OriginFor<T>,474 subs: Vec<(T::AccountId, Data)>,475 ) -> DispatchResultWithPostInfo {476 let sender = ensure_signed(origin)?;477 ensure!(<IdentityOf<T>>::contains_key(&sender), Error::<T>::NotFound);478 ensure!(479 subs.len() <= T::MaxSubAccounts::get() as usize,480 Error::<T>::TooManySubAccounts481 );482483 let (old_deposit, old_ids) = <SubsOf<T>>::get(&sender);484 let new_deposit = T::SubAccountDeposit::get() * <BalanceOf<T>>::from(subs.len() as u32);485486 let not_other_sub = subs487 .iter()488 .filter_map(|i| SuperOf::<T>::get(&i.0))489 .all(|i| i.0 == sender);490 ensure!(not_other_sub, Error::<T>::AlreadyClaimed);491492 match old_deposit.cmp(&new_deposit) {493 core::cmp::Ordering::Less => {494 T::Currency::reserve(&sender, new_deposit - old_deposit)?495 }496 core::cmp::Ordering::Equal => { }497 core::cmp::Ordering::Greater => {498 let err_amount = T::Currency::unreserve(&sender, old_deposit - new_deposit);499 debug_assert!(err_amount.is_zero());500 }501 }502503 for s in old_ids.iter() {504 <SuperOf<T>>::remove(s);505 }506 let mut ids = <SubAccounts<T>>::default();507 for (id, name) in subs {508 <SuperOf<T>>::insert(&id, (sender.clone(), name));509 ids.try_push(id)510 .expect("subs length is less than T::MaxSubAccounts; qed");511 }512 let new_subs = ids.len();513514 if ids.is_empty() {515 <SubsOf<T>>::remove(&sender);516 } else {517 <SubsOf<T>>::insert(&sender, (new_deposit, ids));518 }519520 Ok(Some(521 T::WeightInfo::set_subs_old(old_ids.len() as u32) 522 523 .saturating_add(T::WeightInfo::set_subs_new(new_subs as u32)),524 )525 .into())526 }527528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 #[pallet::call_index(3)]547 #[pallet::weight(T::WeightInfo::clear_identity(548 T::MaxRegistrars::get(), 549 T::MaxSubAccounts::get(), 550 T::MaxAdditionalFields::get(), 551 ))]552 pub fn clear_identity(origin: OriginFor<T>) -> DispatchResultWithPostInfo {553 let sender = ensure_signed(origin)?;554555 let (subs_deposit, sub_ids) = <SubsOf<T>>::take(&sender);556 let id = <IdentityOf<T>>::take(&sender).ok_or(Error::<T>::NotNamed)?;557 let deposit = id.total_deposit() + subs_deposit;558 for sub in sub_ids.iter() {559 <SuperOf<T>>::remove(sub);560 }561562 let err_amount = T::Currency::unreserve(&sender, deposit);563 debug_assert!(err_amount.is_zero());564565 Self::deposit_event(Event::IdentityCleared {566 who: sender,567 deposit,568 });569570 Ok(Some(T::WeightInfo::clear_identity(571 id.judgements.len() as u32, 572 sub_ids.len() as u32, 573 id.info.additional.len() as u32, 574 ))575 .into())576 }577578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 #[pallet::call_index(4)]602 #[pallet::weight(T::WeightInfo::request_judgement(603 T::MaxRegistrars::get(), 604 T::MaxAdditionalFields::get(), 605 ))]606 pub fn request_judgement(607 origin: OriginFor<T>,608 #[pallet::compact] reg_index: RegistrarIndex,609 #[pallet::compact] max_fee: BalanceOf<T>,610 ) -> DispatchResultWithPostInfo {611 let sender = ensure_signed(origin)?;612 let registrars = <Registrars<T>>::get();613 let registrar = registrars614 .get(reg_index as usize)615 .and_then(Option::as_ref)616 .ok_or(Error::<T>::EmptyIndex)?;617 ensure!(max_fee >= registrar.fee, Error::<T>::FeeChanged);618 let mut id = <IdentityOf<T>>::get(&sender).ok_or(Error::<T>::NoIdentity)?;619620 let item = (reg_index, Judgement::FeePaid(registrar.fee));621 match id.judgements.binary_search_by_key(®_index, |x| x.0) {622 Ok(i) => {623 if id.judgements[i].1.is_sticky() {624 return Err(Error::<T>::StickyJudgement.into());625 } else {626 id.judgements[i] = item627 }628 }629 Err(i) => id630 .judgements631 .try_insert(i, item)632 .map_err(|_| Error::<T>::TooManyRegistrars)?,633 }634635 T::Currency::reserve(&sender, registrar.fee)?;636637 let judgements = id.judgements.len();638 let extra_fields = id.info.additional.len();639 <IdentityOf<T>>::insert(&sender, id);640641 Self::deposit_event(Event::JudgementRequested {642 who: sender,643 registrar_index: reg_index,644 });645646 Ok(Some(T::WeightInfo::request_judgement(647 judgements as u32,648 extra_fields as u32,649 ))650 .into())651 }652653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 #[pallet::call_index(5)]671 #[pallet::weight(T::WeightInfo::cancel_request(672 T::MaxRegistrars::get(), 673 T::MaxAdditionalFields::get(), 674 ))]675 pub fn cancel_request(676 origin: OriginFor<T>,677 reg_index: RegistrarIndex,678 ) -> DispatchResultWithPostInfo {679 let sender = ensure_signed(origin)?;680 let mut id = <IdentityOf<T>>::get(&sender).ok_or(Error::<T>::NoIdentity)?;681682 let pos = id683 .judgements684 .binary_search_by_key(®_index, |x| x.0)685 .map_err(|_| Error::<T>::NotFound)?;686 let fee = if let Judgement::FeePaid(fee) = id.judgements.remove(pos).1 {687 fee688 } else {689 return Err(Error::<T>::JudgementGiven.into());690 };691692 let err_amount = T::Currency::unreserve(&sender, fee);693 debug_assert!(err_amount.is_zero());694 let judgements = id.judgements.len();695 let extra_fields = id.info.additional.len();696 <IdentityOf<T>>::insert(&sender, id);697698 Self::deposit_event(Event::JudgementUnrequested {699 who: sender,700 registrar_index: reg_index,701 });702703 Ok(Some(T::WeightInfo::cancel_request(704 judgements as u32,705 extra_fields as u32,706 ))707 .into())708 }709710 711 712 713 714 715 716 717 718 719 720 721 722 723 #[pallet::call_index(6)]724 #[pallet::weight(T::WeightInfo::set_fee(T::MaxRegistrars::get()))] 725 pub fn set_fee(726 origin: OriginFor<T>,727 #[pallet::compact] index: RegistrarIndex,728 #[pallet::compact] fee: BalanceOf<T>,729 ) -> DispatchResultWithPostInfo {730 let who = ensure_signed(origin)?;731732 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {733 rs.get_mut(index as usize)734 .and_then(|x| x.as_mut())735 .and_then(|r| {736 if r.account == who {737 r.fee = fee;738 Some(())739 } else {740 None741 }742 })743 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;744 Ok(rs.len())745 })?;746 Ok(Some(T::WeightInfo::set_fee(registrars as u32)).into()) 747 }748749 750 751 752 753 754 755 756 757 758 759 760 761 762 #[pallet::call_index(7)]763 #[pallet::weight(T::WeightInfo::set_account_id(T::MaxRegistrars::get()))] 764 pub fn set_account_id(765 origin: OriginFor<T>,766 #[pallet::compact] index: RegistrarIndex,767 new: AccountIdLookupOf<T>,768 ) -> DispatchResultWithPostInfo {769 let who = ensure_signed(origin)?;770 let new = T::Lookup::lookup(new)?;771772 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {773 rs.get_mut(index as usize)774 .and_then(|x| x.as_mut())775 .and_then(|r| {776 if r.account == who {777 r.account = new;778 Some(())779 } else {780 None781 }782 })783 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;784 Ok(rs.len())785 })?;786 Ok(Some(T::WeightInfo::set_account_id(registrars as u32)).into()) 787 }788789 790 791 792 793 794 795 796 797 798 799 800 801 802 #[pallet::call_index(8)]803 #[pallet::weight(T::WeightInfo::set_fields(T::MaxRegistrars::get()))] 804 pub fn set_fields(805 origin: OriginFor<T>,806 #[pallet::compact] index: RegistrarIndex,807 fields: IdentityFields,808 ) -> DispatchResultWithPostInfo {809 let who = ensure_signed(origin)?;810811 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {812 rs.get_mut(index as usize)813 .and_then(|x| x.as_mut())814 .and_then(|r| {815 if r.account == who {816 r.fields = fields;817 Some(())818 } else {819 None820 }821 })822 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;823 Ok(rs.len())824 })?;825 Ok(Some(T::WeightInfo::set_fields(826 registrars as u32, 827 ))828 .into())829 }830831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 #[pallet::call_index(9)]852 #[pallet::weight(T::WeightInfo::provide_judgement(853 T::MaxRegistrars::get(), 854 T::MaxAdditionalFields::get(), 855 ))]856 pub fn provide_judgement(857 origin: OriginFor<T>,858 #[pallet::compact] reg_index: RegistrarIndex,859 target: AccountIdLookupOf<T>,860 judgement: Judgement<BalanceOf<T>>,861 identity: T::Hash,862 ) -> DispatchResultWithPostInfo {863 let sender = ensure_signed(origin)?;864 let target = T::Lookup::lookup(target)?;865 ensure!(!judgement.has_deposit(), Error::<T>::InvalidJudgement);866 <Registrars<T>>::get()867 .get(reg_index as usize)868 .and_then(Option::as_ref)869 .filter(|r| r.account == sender)870 .ok_or(Error::<T>::InvalidIndex)?;871 let mut id = <IdentityOf<T>>::get(&target).ok_or(Error::<T>::InvalidTarget)?;872873 if T::Hashing::hash_of(&id.info) != identity {874 return Err(Error::<T>::JudgementForDifferentIdentity.into());875 }876877 let item = (reg_index, judgement);878 match id.judgements.binary_search_by_key(®_index, |x| x.0) {879 Ok(position) => {880 if let Judgement::FeePaid(fee) = id.judgements[position].1 {881 T::Currency::repatriate_reserved(882 &target,883 &sender,884 fee,885 BalanceStatus::Free,886 )887 .map_err(|_| Error::<T>::JudgementPaymentFailed)?;888 }889 id.judgements[position] = item890 }891 Err(position) => id892 .judgements893 .try_insert(position, item)894 .map_err(|_| Error::<T>::TooManyRegistrars)?,895 }896897 let judgements = id.judgements.len();898 let extra_fields = id.info.additional.len();899 <IdentityOf<T>>::insert(&target, id);900 Self::deposit_event(Event::JudgementGiven {901 target,902 registrar_index: reg_index,903 });904905 Ok(Some(T::WeightInfo::provide_judgement(906 judgements as u32,907 extra_fields as u32,908 ))909 .into())910 }911912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 #[pallet::call_index(10)]932 #[pallet::weight(T::WeightInfo::kill_identity(933 T::MaxRegistrars::get(), 934 T::MaxSubAccounts::get(), 935 T::MaxAdditionalFields::get(), 936 ))]937 pub fn kill_identity(938 origin: OriginFor<T>,939 target: AccountIdLookupOf<T>,940 ) -> DispatchResultWithPostInfo {941 T::ForceOrigin::ensure_origin(origin)?;942943 944 let target = T::Lookup::lookup(target)?;945 946 let (subs_deposit, sub_ids) = <SubsOf<T>>::take(&target);947 let id = <IdentityOf<T>>::take(&target).ok_or(Error::<T>::NotNamed)?;948 let deposit = id.total_deposit() + subs_deposit;949 for sub in sub_ids.iter() {950 <SuperOf<T>>::remove(sub);951 }952 953 T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit).0);954955 Self::deposit_event(Event::IdentityKilled {956 who: target,957 deposit,958 });959960 Ok(Some(T::WeightInfo::kill_identity(961 id.judgements.len() as u32, 962 sub_ids.len() as u32, 963 id.info.additional.len() as u32, 964 ))965 .into())966 }967968 969 970 971 972 973 974 975 #[pallet::call_index(11)]976 #[pallet::weight(T::WeightInfo::add_sub(T::MaxSubAccounts::get()))]977 pub fn add_sub(978 origin: OriginFor<T>,979 sub: AccountIdLookupOf<T>,980 data: Data,981 ) -> DispatchResult {982 let sender = ensure_signed(origin)?;983 let sub = T::Lookup::lookup(sub)?;984 ensure!(985 IdentityOf::<T>::contains_key(&sender),986 Error::<T>::NoIdentity987 );988989 990 ensure!(991 !SuperOf::<T>::contains_key(&sub),992 Error::<T>::AlreadyClaimed993 );994995 SubsOf::<T>::try_mutate(&sender, |(ref mut subs_deposit, ref mut sub_ids)| {996 997 ensure!(998 sub_ids.len() < T::MaxSubAccounts::get() as usize,999 Error::<T>::TooManySubAccounts1000 );1001 let deposit = T::SubAccountDeposit::get();1002 T::Currency::reserve(&sender, deposit)?;10031004 SuperOf::<T>::insert(&sub, (sender.clone(), data));1005 sub_ids1006 .try_push(sub.clone())1007 .expect("sub ids length checked above; qed");1008 *subs_deposit = subs_deposit.saturating_add(deposit);10091010 Self::deposit_event(Event::SubIdentityAdded {1011 sub,1012 main: sender.clone(),1013 deposit,1014 });1015 Ok(())1016 })1017 }10181019 1020 1021 1022 1023 #[pallet::call_index(12)]1024 #[pallet::weight(T::WeightInfo::rename_sub(T::MaxSubAccounts::get()))]1025 pub fn rename_sub(1026 origin: OriginFor<T>,1027 sub: AccountIdLookupOf<T>,1028 data: Data,1029 ) -> DispatchResult {1030 let sender = ensure_signed(origin)?;1031 let sub = T::Lookup::lookup(sub)?;1032 ensure!(1033 IdentityOf::<T>::contains_key(&sender),1034 Error::<T>::NoIdentity1035 );1036 ensure!(1037 SuperOf::<T>::get(&sub).map_or(false, |x| x.0 == sender),1038 Error::<T>::NotOwned1039 );1040 SuperOf::<T>::insert(&sub, (sender, data));1041 Ok(())1042 }10431044 1045 1046 1047 1048 1049 1050 1051 #[pallet::call_index(13)]1052 #[pallet::weight(T::WeightInfo::remove_sub(T::MaxSubAccounts::get()))]1053 pub fn remove_sub(origin: OriginFor<T>, sub: AccountIdLookupOf<T>) -> DispatchResult {1054 let sender = ensure_signed(origin)?;1055 ensure!(1056 IdentityOf::<T>::contains_key(&sender),1057 Error::<T>::NoIdentity1058 );1059 let sub = T::Lookup::lookup(sub)?;1060 let (sup, _) = SuperOf::<T>::get(&sub).ok_or(Error::<T>::NotSub)?;1061 ensure!(sup == sender, Error::<T>::NotOwned);1062 SuperOf::<T>::remove(&sub);1063 SubsOf::<T>::mutate(&sup, |(ref mut subs_deposit, ref mut sub_ids)| {1064 sub_ids.retain(|x| x != &sub);1065 let deposit = T::SubAccountDeposit::get().min(*subs_deposit);1066 *subs_deposit -= deposit;1067 let err_amount = T::Currency::unreserve(&sender, deposit);1068 debug_assert!(err_amount.is_zero());1069 Self::deposit_event(Event::SubIdentityRemoved {1070 sub,1071 main: sender,1072 deposit,1073 });1074 });1075 Ok(())1076 }10771078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 #[pallet::call_index(14)]1089 #[pallet::weight(T::WeightInfo::quit_sub(T::MaxSubAccounts::get()))]1090 pub fn quit_sub(origin: OriginFor<T>) -> DispatchResult {1091 let sender = ensure_signed(origin)?;1092 let (sup, _) = SuperOf::<T>::take(&sender).ok_or(Error::<T>::NotSub)?;1093 SubsOf::<T>::mutate(&sup, |(ref mut subs_deposit, ref mut sub_ids)| {1094 sub_ids.retain(|x| x != &sender);1095 let deposit = T::SubAccountDeposit::get().min(*subs_deposit);1096 *subs_deposit -= deposit;1097 let _ =1098 T::Currency::repatriate_reserved(&sup, &sender, deposit, BalanceStatus::Free);1099 Self::deposit_event(Event::SubIdentityRevoked {1100 sub: sender,1101 main: sup.clone(),1102 deposit,1103 });1104 });1105 Ok(())1106 }11071108 1109 1110 1111 1112 1113 #[pallet::call_index(15)]1114 #[pallet::weight(T::WeightInfo::force_insert_identities(1115 T::MaxAdditionalFields::get(), 1116 identities.len() as u32, 1117 ))]1118 pub fn force_insert_identities(1119 origin: OriginFor<T>,1120 identities: Vec<(T::AccountId, RegistrationOf<T>)>,1121 ) -> DispatchResult {1122 T::ForceOrigin::ensure_origin(origin)?;1123 for identity in identities.clone() {1124 IdentityOf::<T>::insert(identity.0, identity.1);1125 }1126 Self::deposit_event(Event::IdentitiesInserted {1127 amount: identities.len() as u32,1128 });1129 Ok(())1130 }11311132 1133 1134 1135 1136 1137 #[pallet::call_index(16)]1138 #[pallet::weight(T::WeightInfo::force_remove_identities(1139 T::MaxAdditionalFields::get(), 1140 identities.len() as u32, 1141 ))]1142 pub fn force_remove_identities(1143 origin: OriginFor<T>,1144 identities: Vec<T::AccountId>,1145 ) -> DispatchResult {1146 T::ForceOrigin::ensure_origin(origin)?;1147 for identity in identities.clone() {1148 let (_, sub_ids) = <SubsOf<T>>::take(&identity);1149 <IdentityOf<T>>::remove(&identity);1150 for sub in sub_ids.iter() {1151 <SuperOf<T>>::remove(sub);1152 }1153 }1154 Self::deposit_event(Event::IdentitiesRemoved {1155 amount: identities.len() as u32,1156 });1157 Ok(())1158 }11591160 1161 1162 1163 1164 1165 #[pallet::call_index(17)]1166 #[pallet::weight(T::WeightInfo::force_set_subs(1167 T::MaxSubAccounts::get(), 1168 subs.len() as u32, 1169 ))]1170 pub fn force_set_subs(1171 origin: OriginFor<T>,1172 subs: Vec<SubAccountsByAccountId<T>>,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 = <SubAccounts<T>>::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}