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 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 JudgementRequested {279 who: T::AccountId,280 registrar_index: RegistrarIndex,281 },282 283 JudgementUnrequested {284 who: T::AccountId,285 registrar_index: RegistrarIndex,286 },287 288 JudgementGiven {289 target: T::AccountId,290 registrar_index: RegistrarIndex,291 },292 293 RegistrarAdded { registrar_index: RegistrarIndex },294 295 SubIdentityAdded {296 sub: T::AccountId,297 main: T::AccountId,298 deposit: BalanceOf<T>,299 },300 301 SubIdentityRemoved {302 sub: T::AccountId,303 main: T::AccountId,304 deposit: BalanceOf<T>,305 },306 307 308 SubIdentityRevoked {309 sub: T::AccountId,310 main: T::AccountId,311 deposit: BalanceOf<T>,312 },313 }314315 #[pallet::call]316 317 impl<T: Config> Pallet<T> {318 319 320 321 322 323 324 325 326 327 328 329 330 331 #[pallet::call_index(0)]332 #[pallet::weight(T::WeightInfo::add_registrar(T::MaxRegistrars::get()))]333 pub fn add_registrar(334 origin: OriginFor<T>,335 account: AccountIdLookupOf<T>,336 ) -> DispatchResultWithPostInfo {337 T::RegistrarOrigin::ensure_origin(origin)?;338 let account = T::Lookup::lookup(account)?;339340 let (i, registrar_count) = <Registrars<T>>::try_mutate(341 |registrars| -> Result<(RegistrarIndex, usize), DispatchError> {342 registrars343 .try_push(Some(RegistrarInfo {344 account,345 fee: Zero::zero(),346 fields: Default::default(),347 }))348 .map_err(|_| Error::<T>::TooManyRegistrars)?;349 Ok(((registrars.len() - 1) as RegistrarIndex, registrars.len()))350 },351 )?;352353 Self::deposit_event(Event::RegistrarAdded { registrar_index: i });354355 Ok(Some(T::WeightInfo::add_registrar(registrar_count as u32)).into())356 }357358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 #[pallet::call_index(1)]378 #[pallet::weight( T::WeightInfo::set_identity(379 T::MaxRegistrars::get(), 380 T::MaxAdditionalFields::get(), 381 ))]382 pub fn set_identity(383 origin: OriginFor<T>,384 info: Box<IdentityInfo<T::MaxAdditionalFields>>,385 ) -> DispatchResultWithPostInfo {386 let sender = ensure_signed(origin)?;387 let extra_fields = info.additional.len() as u32;388 ensure!(389 extra_fields <= T::MaxAdditionalFields::get(),390 Error::<T>::TooManyFields391 );392 let fd = <BalanceOf<T>>::from(extra_fields) * T::FieldDeposit::get();393394 let mut id = match <IdentityOf<T>>::get(&sender) {395 Some(mut id) => {396 397 id.judgements.retain(|j| j.1.is_sticky());398 id.info = *info;399 id400 }401 None => Registration {402 info: *info,403 judgements: BoundedVec::default(),404 deposit: Zero::zero(),405 },406 };407408 let old_deposit = id.deposit;409 id.deposit = T::BasicDeposit::get() + fd;410 if id.deposit > old_deposit {411 T::Currency::reserve(&sender, id.deposit - old_deposit)?;412 }413 if old_deposit > id.deposit {414 let err_amount = T::Currency::unreserve(&sender, old_deposit - id.deposit);415 debug_assert!(err_amount.is_zero());416 }417418 let judgements = id.judgements.len();419 <IdentityOf<T>>::insert(&sender, id);420 Self::deposit_event(Event::IdentitySet { who: sender });421422 Ok(Some(T::WeightInfo::set_identity(423 judgements as u32, 424 extra_fields, 425 ))426 .into())427 }428429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 #[pallet::call_index(2)]457 #[pallet::weight(T::WeightInfo::set_subs_old(T::MaxSubAccounts::get()) 458 .saturating_add(T::WeightInfo::set_subs_new(subs.len() as u32)) 459 )]460 pub fn set_subs(461 origin: OriginFor<T>,462 subs: Vec<(T::AccountId, Data)>,463 ) -> DispatchResultWithPostInfo {464 let sender = ensure_signed(origin)?;465 ensure!(<IdentityOf<T>>::contains_key(&sender), Error::<T>::NotFound);466 ensure!(467 subs.len() <= T::MaxSubAccounts::get() as usize,468 Error::<T>::TooManySubAccounts469 );470471 let (old_deposit, old_ids) = <SubsOf<T>>::get(&sender);472 let new_deposit = T::SubAccountDeposit::get() * <BalanceOf<T>>::from(subs.len() as u32);473474 let not_other_sub = subs475 .iter()476 .filter_map(|i| SuperOf::<T>::get(&i.0))477 .all(|i| i.0 == sender);478 ensure!(not_other_sub, Error::<T>::AlreadyClaimed);479480 if old_deposit < new_deposit {481 T::Currency::reserve(&sender, new_deposit - old_deposit)?;482 } else if old_deposit > new_deposit {483 let err_amount = T::Currency::unreserve(&sender, old_deposit - new_deposit);484 debug_assert!(err_amount.is_zero());485 }486 487488 for s in old_ids.iter() {489 <SuperOf<T>>::remove(s);490 }491 let mut ids = BoundedVec::<T::AccountId, T::MaxSubAccounts>::default();492 for (id, name) in subs {493 <SuperOf<T>>::insert(&id, (sender.clone(), name));494 ids.try_push(id)495 .expect("subs length is less than T::MaxSubAccounts; qed");496 }497 let new_subs = ids.len();498499 if ids.is_empty() {500 <SubsOf<T>>::remove(&sender);501 } else {502 <SubsOf<T>>::insert(&sender, (new_deposit, ids));503 }504505 Ok(Some(506 T::WeightInfo::set_subs_old(old_ids.len() as u32) 507 508 .saturating_add(T::WeightInfo::set_subs_new(new_subs as u32)),509 )510 .into())511 }512513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 #[pallet::call_index(3)]532 #[pallet::weight(T::WeightInfo::clear_identity(533 T::MaxRegistrars::get(), 534 T::MaxSubAccounts::get(), 535 T::MaxAdditionalFields::get(), 536 ))]537 pub fn clear_identity(origin: OriginFor<T>) -> DispatchResultWithPostInfo {538 let sender = ensure_signed(origin)?;539540 let (subs_deposit, sub_ids) = <SubsOf<T>>::take(&sender);541 let id = <IdentityOf<T>>::take(&sender).ok_or(Error::<T>::NotNamed)?;542 let deposit = id.total_deposit() + subs_deposit;543 for sub in sub_ids.iter() {544 <SuperOf<T>>::remove(sub);545 }546547 let err_amount = T::Currency::unreserve(&sender, deposit);548 debug_assert!(err_amount.is_zero());549550 Self::deposit_event(Event::IdentityCleared {551 who: sender,552 deposit,553 });554555 Ok(Some(T::WeightInfo::clear_identity(556 id.judgements.len() as u32, 557 sub_ids.len() as u32, 558 id.info.additional.len() as u32, 559 ))560 .into())561 }562563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 #[pallet::call_index(4)]587 #[pallet::weight(T::WeightInfo::request_judgement(588 T::MaxRegistrars::get(), 589 T::MaxAdditionalFields::get(), 590 ))]591 pub fn request_judgement(592 origin: OriginFor<T>,593 #[pallet::compact] reg_index: RegistrarIndex,594 #[pallet::compact] max_fee: BalanceOf<T>,595 ) -> DispatchResultWithPostInfo {596 let sender = ensure_signed(origin)?;597 let registrars = <Registrars<T>>::get();598 let registrar = registrars599 .get(reg_index as usize)600 .and_then(Option::as_ref)601 .ok_or(Error::<T>::EmptyIndex)?;602 ensure!(max_fee >= registrar.fee, Error::<T>::FeeChanged);603 let mut id = <IdentityOf<T>>::get(&sender).ok_or(Error::<T>::NoIdentity)?;604605 let item = (reg_index, Judgement::FeePaid(registrar.fee));606 match id.judgements.binary_search_by_key(®_index, |x| x.0) {607 Ok(i) => {608 if id.judgements[i].1.is_sticky() {609 return Err(Error::<T>::StickyJudgement.into());610 } else {611 id.judgements[i] = item612 }613 }614 Err(i) => id615 .judgements616 .try_insert(i, item)617 .map_err(|_| Error::<T>::TooManyRegistrars)?,618 }619620 T::Currency::reserve(&sender, registrar.fee)?;621622 let judgements = id.judgements.len();623 let extra_fields = id.info.additional.len();624 <IdentityOf<T>>::insert(&sender, id);625626 Self::deposit_event(Event::JudgementRequested {627 who: sender,628 registrar_index: reg_index,629 });630631 Ok(Some(T::WeightInfo::request_judgement(632 judgements as u32,633 extra_fields as u32,634 ))635 .into())636 }637638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 #[pallet::call_index(5)]656 #[pallet::weight(T::WeightInfo::cancel_request(657 T::MaxRegistrars::get(), 658 T::MaxAdditionalFields::get(), 659 ))]660 pub fn cancel_request(661 origin: OriginFor<T>,662 reg_index: RegistrarIndex,663 ) -> DispatchResultWithPostInfo {664 let sender = ensure_signed(origin)?;665 let mut id = <IdentityOf<T>>::get(&sender).ok_or(Error::<T>::NoIdentity)?;666667 let pos = id668 .judgements669 .binary_search_by_key(®_index, |x| x.0)670 .map_err(|_| Error::<T>::NotFound)?;671 let fee = if let Judgement::FeePaid(fee) = id.judgements.remove(pos).1 {672 fee673 } else {674 return Err(Error::<T>::JudgementGiven.into());675 };676677 let err_amount = T::Currency::unreserve(&sender, fee);678 debug_assert!(err_amount.is_zero());679 let judgements = id.judgements.len();680 let extra_fields = id.info.additional.len();681 <IdentityOf<T>>::insert(&sender, id);682683 Self::deposit_event(Event::JudgementUnrequested {684 who: sender,685 registrar_index: reg_index,686 });687688 Ok(Some(T::WeightInfo::cancel_request(689 judgements as u32,690 extra_fields as u32,691 ))692 .into())693 }694695 696 697 698 699 700 701 702 703 704 705 706 707 708 #[pallet::call_index(6)]709 #[pallet::weight(T::WeightInfo::set_fee(T::MaxRegistrars::get()))] 710 pub fn set_fee(711 origin: OriginFor<T>,712 #[pallet::compact] index: RegistrarIndex,713 #[pallet::compact] fee: BalanceOf<T>,714 ) -> DispatchResultWithPostInfo {715 let who = ensure_signed(origin)?;716717 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {718 rs.get_mut(index as usize)719 .and_then(|x| x.as_mut())720 .and_then(|r| {721 if r.account == who {722 r.fee = fee;723 Some(())724 } else {725 None726 }727 })728 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;729 Ok(rs.len())730 })?;731 Ok(Some(T::WeightInfo::set_fee(registrars as u32)).into()) 732 }733734 735 736 737 738 739 740 741 742 743 744 745 746 747 #[pallet::call_index(7)]748 #[pallet::weight(T::WeightInfo::set_account_id(T::MaxRegistrars::get()))] 749 pub fn set_account_id(750 origin: OriginFor<T>,751 #[pallet::compact] index: RegistrarIndex,752 new: AccountIdLookupOf<T>,753 ) -> DispatchResultWithPostInfo {754 let who = ensure_signed(origin)?;755 let new = T::Lookup::lookup(new)?;756757 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {758 rs.get_mut(index as usize)759 .and_then(|x| x.as_mut())760 .and_then(|r| {761 if r.account == who {762 r.account = new;763 Some(())764 } else {765 None766 }767 })768 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;769 Ok(rs.len())770 })?;771 Ok(Some(T::WeightInfo::set_account_id(registrars as u32)).into()) 772 }773774 775 776 777 778 779 780 781 782 783 784 785 786 787 #[pallet::call_index(8)]788 #[pallet::weight(T::WeightInfo::set_fields(T::MaxRegistrars::get()))] 789 pub fn set_fields(790 origin: OriginFor<T>,791 #[pallet::compact] index: RegistrarIndex,792 fields: IdentityFields,793 ) -> DispatchResultWithPostInfo {794 let who = ensure_signed(origin)?;795796 let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {797 rs.get_mut(index as usize)798 .and_then(|x| x.as_mut())799 .and_then(|r| {800 if r.account == who {801 r.fields = fields;802 Some(())803 } else {804 None805 }806 })807 .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;808 Ok(rs.len())809 })?;810 Ok(Some(T::WeightInfo::set_fields(811 registrars as u32, 812 ))813 .into())814 }815816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 #[pallet::call_index(9)]837 #[pallet::weight(T::WeightInfo::provide_judgement(838 T::MaxRegistrars::get(), 839 T::MaxAdditionalFields::get(), 840 ))]841 pub fn provide_judgement(842 origin: OriginFor<T>,843 #[pallet::compact] reg_index: RegistrarIndex,844 target: AccountIdLookupOf<T>,845 judgement: Judgement<BalanceOf<T>>,846 identity: T::Hash,847 ) -> DispatchResultWithPostInfo {848 let sender = ensure_signed(origin)?;849 let target = T::Lookup::lookup(target)?;850 ensure!(!judgement.has_deposit(), Error::<T>::InvalidJudgement);851 <Registrars<T>>::get()852 .get(reg_index as usize)853 .and_then(Option::as_ref)854 .filter(|r| r.account == sender)855 .ok_or(Error::<T>::InvalidIndex)?;856 let mut id = <IdentityOf<T>>::get(&target).ok_or(Error::<T>::InvalidTarget)?;857858 if T::Hashing::hash_of(&id.info) != identity {859 return Err(Error::<T>::JudgementForDifferentIdentity.into());860 }861862 let item = (reg_index, judgement);863 match id.judgements.binary_search_by_key(®_index, |x| x.0) {864 Ok(position) => {865 if let Judgement::FeePaid(fee) = id.judgements[position].1 {866 T::Currency::repatriate_reserved(867 &target,868 &sender,869 fee,870 BalanceStatus::Free,871 )872 .map_err(|_| Error::<T>::JudgementPaymentFailed)?;873 }874 id.judgements[position] = item875 }876 Err(position) => id877 .judgements878 .try_insert(position, item)879 .map_err(|_| Error::<T>::TooManyRegistrars)?,880 }881882 let judgements = id.judgements.len();883 let extra_fields = id.info.additional.len();884 <IdentityOf<T>>::insert(&target, id);885 Self::deposit_event(Event::JudgementGiven {886 target,887 registrar_index: reg_index,888 });889890 Ok(Some(T::WeightInfo::provide_judgement(891 judgements as u32,892 extra_fields as u32,893 ))894 .into())895 }896897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 #[pallet::call_index(10)]917 #[pallet::weight(T::WeightInfo::kill_identity(918 T::MaxRegistrars::get(), 919 T::MaxSubAccounts::get(), 920 T::MaxAdditionalFields::get(), 921 ))]922 pub fn kill_identity(923 origin: OriginFor<T>,924 target: AccountIdLookupOf<T>,925 ) -> DispatchResultWithPostInfo {926 T::ForceOrigin::ensure_origin(origin)?;927928 929 let target = T::Lookup::lookup(target)?;930 931 let (subs_deposit, sub_ids) = <SubsOf<T>>::take(&target);932 let id = <IdentityOf<T>>::take(&target).ok_or(Error::<T>::NotNamed)?;933 let deposit = id.total_deposit() + subs_deposit;934 for sub in sub_ids.iter() {935 <SuperOf<T>>::remove(sub);936 }937 938 T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit).0);939940 Self::deposit_event(Event::IdentityKilled {941 who: target,942 deposit,943 });944945 Ok(Some(T::WeightInfo::kill_identity(946 id.judgements.len() as u32, 947 sub_ids.len() as u32, 948 id.info.additional.len() as u32, 949 ))950 .into())951 }952953 954 955 956 957 958 959 960 #[pallet::call_index(11)]961 #[pallet::weight(T::WeightInfo::add_sub(T::MaxSubAccounts::get()))]962 pub fn add_sub(963 origin: OriginFor<T>,964 sub: AccountIdLookupOf<T>,965 data: Data,966 ) -> DispatchResult {967 let sender = ensure_signed(origin)?;968 let sub = T::Lookup::lookup(sub)?;969 ensure!(970 IdentityOf::<T>::contains_key(&sender),971 Error::<T>::NoIdentity972 );973974 975 ensure!(976 !SuperOf::<T>::contains_key(&sub),977 Error::<T>::AlreadyClaimed978 );979980 SubsOf::<T>::try_mutate(&sender, |(ref mut subs_deposit, ref mut sub_ids)| {981 982 ensure!(983 sub_ids.len() < T::MaxSubAccounts::get() as usize,984 Error::<T>::TooManySubAccounts985 );986 let deposit = T::SubAccountDeposit::get();987 T::Currency::reserve(&sender, deposit)?;988989 SuperOf::<T>::insert(&sub, (sender.clone(), data));990 sub_ids991 .try_push(sub.clone())992 .expect("sub ids length checked above; qed");993 *subs_deposit = subs_deposit.saturating_add(deposit);994995 Self::deposit_event(Event::SubIdentityAdded {996 sub,997 main: sender.clone(),998 deposit,999 });1000 Ok(())1001 })1002 }10031004 1005 1006 1007 1008 #[pallet::call_index(12)]1009 #[pallet::weight(T::WeightInfo::rename_sub(T::MaxSubAccounts::get()))]1010 pub fn rename_sub(1011 origin: OriginFor<T>,1012 sub: AccountIdLookupOf<T>,1013 data: Data,1014 ) -> DispatchResult {1015 let sender = ensure_signed(origin)?;1016 let sub = T::Lookup::lookup(sub)?;1017 ensure!(1018 IdentityOf::<T>::contains_key(&sender),1019 Error::<T>::NoIdentity1020 );1021 ensure!(1022 SuperOf::<T>::get(&sub).map_or(false, |x| x.0 == sender),1023 Error::<T>::NotOwned1024 );1025 SuperOf::<T>::insert(&sub, (sender, data));1026 Ok(())1027 }10281029 1030 1031 1032 1033 1034 1035 1036 #[pallet::call_index(13)]1037 #[pallet::weight(T::WeightInfo::remove_sub(T::MaxSubAccounts::get()))]1038 pub fn remove_sub(origin: OriginFor<T>, sub: AccountIdLookupOf<T>) -> DispatchResult {1039 let sender = ensure_signed(origin)?;1040 ensure!(1041 IdentityOf::<T>::contains_key(&sender),1042 Error::<T>::NoIdentity1043 );1044 let sub = T::Lookup::lookup(sub)?;1045 let (sup, _) = SuperOf::<T>::get(&sub).ok_or(Error::<T>::NotSub)?;1046 ensure!(sup == sender, Error::<T>::NotOwned);1047 SuperOf::<T>::remove(&sub);1048 SubsOf::<T>::mutate(&sup, |(ref mut subs_deposit, ref mut sub_ids)| {1049 sub_ids.retain(|x| x != &sub);1050 let deposit = T::SubAccountDeposit::get().min(*subs_deposit);1051 *subs_deposit -= deposit;1052 let err_amount = T::Currency::unreserve(&sender, deposit);1053 debug_assert!(err_amount.is_zero());1054 Self::deposit_event(Event::SubIdentityRemoved {1055 sub,1056 main: sender,1057 deposit,1058 });1059 });1060 Ok(())1061 }10621063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 #[pallet::call_index(14)]1074 #[pallet::weight(T::WeightInfo::quit_sub(T::MaxSubAccounts::get()))]1075 pub fn quit_sub(origin: OriginFor<T>) -> DispatchResult {1076 let sender = ensure_signed(origin)?;1077 let (sup, _) = SuperOf::<T>::take(&sender).ok_or(Error::<T>::NotSub)?;1078 SubsOf::<T>::mutate(&sup, |(ref mut subs_deposit, ref mut sub_ids)| {1079 sub_ids.retain(|x| x != &sender);1080 let deposit = T::SubAccountDeposit::get().min(*subs_deposit);1081 *subs_deposit -= deposit;1082 let _ =1083 T::Currency::repatriate_reserved(&sup, &sender, deposit, BalanceStatus::Free);1084 Self::deposit_event(Event::SubIdentityRevoked {1085 sub: sender,1086 main: sup.clone(),1087 deposit,1088 });1089 });1090 Ok(())1091 }10921093 1094 #[pallet::call_index(15)]1095 #[pallet::weight(T::WeightInfo::set_identities(1096 T::MaxAdditionalFields::get(), 1097 identities.len() as u32, 1098 ))] 1099 pub fn set_identities(1100 origin: OriginFor<T>,1101 identities: Vec<(1102 T::AccountId,1103 Option<Registration<BalanceOf<T>, T::MaxRegistrars, T::MaxAdditionalFields>>,1104 )>,1105 ) -> DispatchResult {1106 T::ForceOrigin::ensure_origin(origin)?;1107 for identity in identities {1108 IdentityOf::<T>::set(identity.0, identity.1);1109 }1110 Ok(())1111 }1112 }1113}11141115impl<T: Config> Pallet<T> {1116 1117 pub fn subs(who: &T::AccountId) -> Vec<(T::AccountId, Data)> {1118 SubsOf::<T>::get(who)1119 .11120 .into_iter()1121 .filter_map(|a| SuperOf::<T>::get(&a).map(|x| (a, x.1)))1122 .collect()1123 }11241125 1126 pub fn has_identity(who: &T::AccountId, fields: u64) -> bool {1127 IdentityOf::<T>::get(who).map_or(false, |registration| {1128 (registration.info.fields().0.bits() & fields) == fields1129 })1130 }1131}