1#![cfg_attr(not(feature = "std"), no_std)]
31
32mod benchmarking;
33mod tests;
34pub mod weights;
35
36extern crate alloc;
37use alloc::{boxed::Box, vec};
38use frame::{
39 prelude::*,
40 traits::{Currency, InstanceFilter, ReservableCurrency},
41};
42pub use pezpallet::*;
43pub use weights::WeightInfo;
44
45type CallHashOf<T> = <<T as Config>::CallHasher as Hash>::Output;
46
47type BalanceOf<T> =
48 <<T as Config>::Currency as Currency<<T as pezframe_system::Config>::AccountId>>::Balance;
49
50pub type BlockNumberFor<T> =
51 <<T as Config>::BlockNumberProvider as BlockNumberProvider>::BlockNumber;
52
53type AccountIdLookupOf<T> = <<T as pezframe_system::Config>::Lookup as StaticLookup>::Source;
54
55#[derive(
58 Encode,
59 Decode,
60 DecodeWithMemTracking,
61 Clone,
62 Copy,
63 Eq,
64 PartialEq,
65 Ord,
66 PartialOrd,
67 RuntimeDebug,
68 MaxEncodedLen,
69 TypeInfo,
70)]
71pub struct ProxyDefinition<AccountId, ProxyType, BlockNumber> {
72 pub delegate: AccountId,
74 pub proxy_type: ProxyType,
76 pub delay: BlockNumber,
79}
80
81#[derive(
83 Encode,
84 Decode,
85 DecodeWithMemTracking,
86 Clone,
87 Copy,
88 Eq,
89 PartialEq,
90 RuntimeDebug,
91 MaxEncodedLen,
92 TypeInfo,
93)]
94pub struct Announcement<AccountId, Hash, BlockNumber> {
95 real: AccountId,
97 call_hash: Hash,
99 height: BlockNumber,
101}
102
103#[derive(
105 Encode,
106 Decode,
107 Clone,
108 Copy,
109 Eq,
110 PartialEq,
111 RuntimeDebug,
112 MaxEncodedLen,
113 TypeInfo,
114 DecodeWithMemTracking,
115)]
116pub enum DepositKind {
117 Proxies,
119 Announcements,
121}
122
123#[frame::pezpallet]
124pub mod pezpallet {
125 use super::*;
126
127 #[pezpallet::pezpallet]
128 pub struct Pezpallet<T>(_);
129
130 #[pezpallet::config]
132 pub trait Config: pezframe_system::Config {
133 #[allow(deprecated)]
135 type RuntimeEvent: From<Event<Self>>
136 + IsType<<Self as pezframe_system::Config>::RuntimeEvent>;
137
138 type RuntimeCall: Parameter
140 + Dispatchable<RuntimeOrigin = Self::RuntimeOrigin>
141 + GetDispatchInfo
142 + From<pezframe_system::Call<Self>>
143 + IsSubType<Call<Self>>
144 + IsType<<Self as pezframe_system::Config>::RuntimeCall>;
145
146 type Currency: ReservableCurrency<Self::AccountId>;
148
149 type ProxyType: Parameter
154 + Member
155 + Ord
156 + PartialOrd
157 + frame::traits::InstanceFilter<<Self as Config>::RuntimeCall>
158 + Default
159 + MaxEncodedLen;
160
161 #[pezpallet::constant]
166 type ProxyDepositBase: Get<BalanceOf<Self>>;
167
168 #[pezpallet::constant]
174 type ProxyDepositFactor: Get<BalanceOf<Self>>;
175
176 #[pezpallet::constant]
178 type MaxProxies: Get<u32>;
179
180 type WeightInfo: WeightInfo;
182
183 #[pezpallet::constant]
185 type MaxPending: Get<u32>;
186
187 type CallHasher: Hash;
189
190 #[pezpallet::constant]
195 type AnnouncementDepositBase: Get<BalanceOf<Self>>;
196
197 #[pezpallet::constant]
202 type AnnouncementDepositFactor: Get<BalanceOf<Self>>;
203
204 type BlockNumberProvider: BlockNumberProvider;
227 }
228
229 #[pezpallet::call]
230 impl<T: Config> Pezpallet<T> {
231 #[pezpallet::call_index(0)]
241 #[pezpallet::weight({
242 let di = call.get_dispatch_info();
243 (T::WeightInfo::proxy(T::MaxProxies::get())
244 .saturating_add(T::DbWeight::get().reads_writes(1, 1))
246 .saturating_add(di.call_weight),
247 di.class)
248 })]
249 pub fn proxy(
250 origin: OriginFor<T>,
251 real: AccountIdLookupOf<T>,
252 force_proxy_type: Option<T::ProxyType>,
253 call: Box<<T as Config>::RuntimeCall>,
254 ) -> DispatchResult {
255 let who = ensure_signed(origin)?;
256 let real = T::Lookup::lookup(real)?;
257 let def = Self::find_proxy(&real, &who, force_proxy_type)?;
258 ensure!(def.delay.is_zero(), Error::<T>::Unannounced);
259
260 Self::do_proxy(def, real, *call);
261
262 Ok(())
263 }
264
265 #[pezpallet::call_index(1)]
275 #[pezpallet::weight(T::WeightInfo::add_proxy(T::MaxProxies::get()))]
276 pub fn add_proxy(
277 origin: OriginFor<T>,
278 delegate: AccountIdLookupOf<T>,
279 proxy_type: T::ProxyType,
280 delay: BlockNumberFor<T>,
281 ) -> DispatchResult {
282 let who = ensure_signed(origin)?;
283 let delegate = T::Lookup::lookup(delegate)?;
284 Self::add_proxy_delegate(&who, delegate, proxy_type, delay)
285 }
286
287 #[pezpallet::call_index(2)]
295 #[pezpallet::weight(T::WeightInfo::remove_proxy(T::MaxProxies::get()))]
296 pub fn remove_proxy(
297 origin: OriginFor<T>,
298 delegate: AccountIdLookupOf<T>,
299 proxy_type: T::ProxyType,
300 delay: BlockNumberFor<T>,
301 ) -> DispatchResult {
302 let who = ensure_signed(origin)?;
303 let delegate = T::Lookup::lookup(delegate)?;
304 Self::remove_proxy_delegate(&who, delegate, proxy_type, delay)
305 }
306
307 #[pezpallet::call_index(3)]
314 #[pezpallet::weight(T::WeightInfo::remove_proxies(T::MaxProxies::get()))]
315 pub fn remove_proxies(origin: OriginFor<T>) -> DispatchResult {
316 let who = ensure_signed(origin)?;
317 Self::remove_all_proxy_delegates(&who);
318 Ok(())
319 }
320
321 #[pezpallet::call_index(4)]
340 #[pezpallet::weight(T::WeightInfo::create_pure(T::MaxProxies::get()))]
341 pub fn create_pure(
342 origin: OriginFor<T>,
343 proxy_type: T::ProxyType,
344 delay: BlockNumberFor<T>,
345 index: u16,
346 ) -> DispatchResult {
347 let who = ensure_signed(origin)?;
348
349 let pure = Self::pure_account(&who, &proxy_type, index, None);
350 ensure!(!Proxies::<T>::contains_key(&pure), Error::<T>::Duplicate);
351
352 let proxy_def =
353 ProxyDefinition { delegate: who.clone(), proxy_type: proxy_type.clone(), delay };
354 let bounded_proxies: BoundedVec<_, T::MaxProxies> =
355 vec![proxy_def].try_into().map_err(|_| Error::<T>::TooMany)?;
356
357 let deposit = T::ProxyDepositBase::get() + T::ProxyDepositFactor::get();
358 T::Currency::reserve(&who, deposit)?;
359
360 Proxies::<T>::insert(&pure, (bounded_proxies, deposit));
361 let extrinsic_index =
362 <pezframe_system::Pezpallet<T>>::extrinsic_index().unwrap_or_default();
363 Self::deposit_event(Event::PureCreated {
364 pure,
365 who,
366 proxy_type,
367 disambiguation_index: index,
368 at: T::BlockNumberProvider::current_block_number(),
369 extrinsic_index,
370 });
371
372 Ok(())
373 }
374
375 #[pezpallet::call_index(5)]
392 #[pezpallet::weight(T::WeightInfo::kill_pure(T::MaxProxies::get()))]
393 pub fn kill_pure(
394 origin: OriginFor<T>,
395 spawner: AccountIdLookupOf<T>,
396 proxy_type: T::ProxyType,
397 index: u16,
398 #[pezpallet::compact] height: BlockNumberFor<T>,
399 #[pezpallet::compact] ext_index: u32,
400 ) -> DispatchResult {
401 let who = ensure_signed(origin)?;
402 let spawner = T::Lookup::lookup(spawner)?;
403
404 let when = (height, ext_index);
405 let proxy = Self::pure_account(&spawner, &proxy_type, index, Some(when));
406 ensure!(proxy == who, Error::<T>::NoPermission);
407
408 let (_, deposit) = Proxies::<T>::take(&who);
409 T::Currency::unreserve(&spawner, deposit);
410
411 Self::deposit_event(Event::PureKilled {
412 pure: who,
413 spawner,
414 proxy_type,
415 disambiguation_index: index,
416 });
417
418 Ok(())
419 }
420
421 #[pezpallet::call_index(6)]
437 #[pezpallet::weight(T::WeightInfo::announce(T::MaxPending::get(), T::MaxProxies::get()))]
438 pub fn announce(
439 origin: OriginFor<T>,
440 real: AccountIdLookupOf<T>,
441 call_hash: CallHashOf<T>,
442 ) -> DispatchResult {
443 let who = ensure_signed(origin)?;
444 let real = T::Lookup::lookup(real)?;
445 Proxies::<T>::get(&real)
446 .0
447 .into_iter()
448 .find(|x| x.delegate == who)
449 .ok_or(Error::<T>::NotProxy)?;
450
451 let announcement = Announcement {
452 real: real.clone(),
453 call_hash,
454 height: T::BlockNumberProvider::current_block_number(),
455 };
456
457 Announcements::<T>::try_mutate(&who, |(ref mut pending, ref mut deposit)| {
458 pending.try_push(announcement).map_err(|_| Error::<T>::TooMany)?;
459 Self::rejig_deposit(
460 &who,
461 *deposit,
462 T::AnnouncementDepositBase::get(),
463 T::AnnouncementDepositFactor::get(),
464 pending.len(),
465 )
466 .map(|d| {
467 d.expect("Just pushed; pending.len() > 0; rejig_deposit returns Some; qed")
468 })
469 .map(|d| *deposit = d)
470 })?;
471 Self::deposit_event(Event::Announced { real, proxy: who, call_hash });
472
473 Ok(())
474 }
475
476 #[pezpallet::call_index(7)]
487 #[pezpallet::weight(T::WeightInfo::remove_announcement(
488 T::MaxPending::get(),
489 T::MaxProxies::get()
490 ))]
491 pub fn remove_announcement(
492 origin: OriginFor<T>,
493 real: AccountIdLookupOf<T>,
494 call_hash: CallHashOf<T>,
495 ) -> DispatchResult {
496 let who = ensure_signed(origin)?;
497 let real = T::Lookup::lookup(real)?;
498 Self::edit_announcements(&who, |ann| ann.real != real || ann.call_hash != call_hash)?;
499
500 Ok(())
501 }
502
503 #[pezpallet::call_index(8)]
514 #[pezpallet::weight(T::WeightInfo::reject_announcement(
515 T::MaxPending::get(),
516 T::MaxProxies::get()
517 ))]
518 pub fn reject_announcement(
519 origin: OriginFor<T>,
520 delegate: AccountIdLookupOf<T>,
521 call_hash: CallHashOf<T>,
522 ) -> DispatchResult {
523 let who = ensure_signed(origin)?;
524 let delegate = T::Lookup::lookup(delegate)?;
525 Self::edit_announcements(&delegate, |ann| {
526 ann.real != who || ann.call_hash != call_hash
527 })?;
528
529 Ok(())
530 }
531
532 #[pezpallet::call_index(9)]
544 #[pezpallet::weight({
545 let di = call.get_dispatch_info();
546 (T::WeightInfo::proxy_announced(T::MaxPending::get(), T::MaxProxies::get())
547 .saturating_add(T::DbWeight::get().reads_writes(1, 1))
549 .saturating_add(di.call_weight),
550 di.class)
551 })]
552 pub fn proxy_announced(
553 origin: OriginFor<T>,
554 delegate: AccountIdLookupOf<T>,
555 real: AccountIdLookupOf<T>,
556 force_proxy_type: Option<T::ProxyType>,
557 call: Box<<T as Config>::RuntimeCall>,
558 ) -> DispatchResult {
559 ensure_signed(origin)?;
560 let delegate = T::Lookup::lookup(delegate)?;
561 let real = T::Lookup::lookup(real)?;
562 let def = Self::find_proxy(&real, &delegate, force_proxy_type)?;
563
564 let call_hash = T::CallHasher::hash_of(&call);
565 let now = T::BlockNumberProvider::current_block_number();
566 Self::edit_announcements(&delegate, |ann| {
567 ann.real != real
568 || ann.call_hash != call_hash
569 || now.saturating_sub(ann.height) < def.delay
570 })
571 .map_err(|_| Error::<T>::Unannounced)?;
572
573 Self::do_proxy(def, real, *call);
574
575 Ok(())
576 }
577
578 #[pezpallet::call_index(10)]
587 #[pezpallet::weight(T::WeightInfo::poke_deposit())]
588 pub fn poke_deposit(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
589 let who = ensure_signed(origin)?;
590 let mut deposit_updated = false;
591
592 Proxies::<T>::try_mutate_exists(&who, |maybe_proxies| -> DispatchResult {
594 let (proxies, old_deposit) = maybe_proxies.take().unwrap_or_default();
595 let maybe_new_deposit = Self::rejig_deposit(
596 &who,
597 old_deposit,
598 T::ProxyDepositBase::get(),
599 T::ProxyDepositFactor::get(),
600 proxies.len(),
601 )?;
602
603 match maybe_new_deposit {
604 Some(new_deposit) if new_deposit != old_deposit => {
605 *maybe_proxies = Some((proxies, new_deposit));
606 deposit_updated = true;
607 Self::deposit_event(Event::DepositPoked {
608 who: who.clone(),
609 kind: DepositKind::Proxies,
610 old_deposit,
611 new_deposit,
612 });
613 },
614 Some(_) => {
615 *maybe_proxies = Some((proxies, old_deposit));
616 },
617 None => {
618 *maybe_proxies = None;
619 if !old_deposit.is_zero() {
620 deposit_updated = true;
621 Self::deposit_event(Event::DepositPoked {
622 who: who.clone(),
623 kind: DepositKind::Proxies,
624 old_deposit,
625 new_deposit: BalanceOf::<T>::zero(),
626 });
627 }
628 },
629 }
630 Ok(())
631 })?;
632
633 Announcements::<T>::try_mutate_exists(&who, |maybe_announcements| -> DispatchResult {
635 let (announcements, old_deposit) = maybe_announcements.take().unwrap_or_default();
636 let maybe_new_deposit = Self::rejig_deposit(
637 &who,
638 old_deposit,
639 T::AnnouncementDepositBase::get(),
640 T::AnnouncementDepositFactor::get(),
641 announcements.len(),
642 )?;
643
644 match maybe_new_deposit {
645 Some(new_deposit) if new_deposit != old_deposit => {
646 *maybe_announcements = Some((announcements, new_deposit));
647 deposit_updated = true;
648 Self::deposit_event(Event::DepositPoked {
649 who: who.clone(),
650 kind: DepositKind::Announcements,
651 old_deposit,
652 new_deposit,
653 });
654 },
655 Some(_) => {
656 *maybe_announcements = Some((announcements, old_deposit));
657 },
658 None => {
659 *maybe_announcements = None;
660 if !old_deposit.is_zero() {
661 deposit_updated = true;
662 Self::deposit_event(Event::DepositPoked {
663 who: who.clone(),
664 kind: DepositKind::Announcements,
665 old_deposit,
666 new_deposit: BalanceOf::<T>::zero(),
667 });
668 }
669 },
670 }
671 Ok(())
672 })?;
673
674 Ok(if deposit_updated { Pays::No.into() } else { Pays::Yes.into() })
675 }
676 }
677
678 #[pezpallet::event]
679 #[pezpallet::generate_deposit(pub(super) fn deposit_event)]
680 pub enum Event<T: Config> {
681 ProxyExecuted { result: DispatchResult },
683 PureCreated {
686 pure: T::AccountId,
687 who: T::AccountId,
688 proxy_type: T::ProxyType,
689 disambiguation_index: u16,
690 at: BlockNumberFor<T>,
691 extrinsic_index: u32,
692 },
693 PureKilled {
695 pure: T::AccountId,
697 spawner: T::AccountId,
699 proxy_type: T::ProxyType,
701 disambiguation_index: u16,
703 },
704 Announced { real: T::AccountId, proxy: T::AccountId, call_hash: CallHashOf<T> },
706 ProxyAdded {
708 delegator: T::AccountId,
709 delegatee: T::AccountId,
710 proxy_type: T::ProxyType,
711 delay: BlockNumberFor<T>,
712 },
713 ProxyRemoved {
715 delegator: T::AccountId,
716 delegatee: T::AccountId,
717 proxy_type: T::ProxyType,
718 delay: BlockNumberFor<T>,
719 },
720 DepositPoked {
722 who: T::AccountId,
723 kind: DepositKind,
724 old_deposit: BalanceOf<T>,
725 new_deposit: BalanceOf<T>,
726 },
727 }
728
729 #[pezpallet::error]
730 pub enum Error<T> {
731 TooMany,
733 NotFound,
735 NotProxy,
737 Unproxyable,
739 Duplicate,
741 NoPermission,
743 Unannounced,
745 NoSelfProxy,
747 }
748
749 #[pezpallet::storage]
752 pub type Proxies<T: Config> = StorageMap<
753 _,
754 Twox64Concat,
755 T::AccountId,
756 (
757 BoundedVec<
758 ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>,
759 T::MaxProxies,
760 >,
761 BalanceOf<T>,
762 ),
763 ValueQuery,
764 >;
765
766 #[pezpallet::storage]
768 pub type Announcements<T: Config> = StorageMap<
769 _,
770 Twox64Concat,
771 T::AccountId,
772 (
773 BoundedVec<Announcement<T::AccountId, CallHashOf<T>, BlockNumberFor<T>>, T::MaxPending>,
774 BalanceOf<T>,
775 ),
776 ValueQuery,
777 >;
778
779 #[pezpallet::view_functions]
780 impl<T: Config> Pezpallet<T> {
781 pub fn check_permissions(
783 call: <T as Config>::RuntimeCall,
784 proxy_type: T::ProxyType,
785 ) -> bool {
786 proxy_type.filter(&call)
787 }
788
789 pub fn is_superset(to_check: T::ProxyType, against: T::ProxyType) -> bool {
791 to_check.is_superset(&against)
792 }
793 }
794}
795
796impl<T: Config> Pezpallet<T> {
797 pub fn proxies(
799 account: T::AccountId,
800 ) -> (
801 BoundedVec<ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>, T::MaxProxies>,
802 BalanceOf<T>,
803 ) {
804 Proxies::<T>::get(account)
805 }
806
807 pub fn announcements(
809 account: T::AccountId,
810 ) -> (
811 BoundedVec<Announcement<T::AccountId, CallHashOf<T>, BlockNumberFor<T>>, T::MaxPending>,
812 BalanceOf<T>,
813 ) {
814 Announcements::<T>::get(account)
815 }
816
817 pub fn pure_account(
829 who: &T::AccountId,
830 proxy_type: &T::ProxyType,
831 index: u16,
832 maybe_when: Option<(BlockNumberFor<T>, u32)>,
833 ) -> T::AccountId {
834 let (height, ext_index) = maybe_when.unwrap_or_else(|| {
835 (
836 T::BlockNumberProvider::current_block_number(),
837 pezframe_system::Pezpallet::<T>::extrinsic_index().unwrap_or_default(),
838 )
839 });
840
841 let entropy = (b"modlpy/proxy____", who, height, ext_index, proxy_type, index)
842 .using_encoded(blake2_256);
843 Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref()))
844 .expect("infinite length input; no invalid inputs for type; qed")
845 }
846
847 pub fn add_proxy_delegate(
856 delegator: &T::AccountId,
857 delegatee: T::AccountId,
858 proxy_type: T::ProxyType,
859 delay: BlockNumberFor<T>,
860 ) -> DispatchResult {
861 ensure!(delegator != &delegatee, Error::<T>::NoSelfProxy);
862 Proxies::<T>::try_mutate(delegator, |(ref mut proxies, ref mut deposit)| {
863 let proxy_def = ProxyDefinition {
864 delegate: delegatee.clone(),
865 proxy_type: proxy_type.clone(),
866 delay,
867 };
868 let i = proxies.binary_search(&proxy_def).err().ok_or(Error::<T>::Duplicate)?;
869 proxies.try_insert(i, proxy_def).map_err(|_| Error::<T>::TooMany)?;
870 let new_deposit = Self::deposit(proxies.len() as u32);
871 if new_deposit > *deposit {
872 T::Currency::reserve(delegator, new_deposit - *deposit)?;
873 } else if new_deposit < *deposit {
874 T::Currency::unreserve(delegator, *deposit - new_deposit);
875 }
876 *deposit = new_deposit;
877 Self::deposit_event(Event::<T>::ProxyAdded {
878 delegator: delegator.clone(),
879 delegatee,
880 proxy_type,
881 delay,
882 });
883 Ok(())
884 })
885 }
886
887 pub fn remove_proxy_delegate(
896 delegator: &T::AccountId,
897 delegatee: T::AccountId,
898 proxy_type: T::ProxyType,
899 delay: BlockNumberFor<T>,
900 ) -> DispatchResult {
901 Proxies::<T>::try_mutate_exists(delegator, |x| {
902 let (mut proxies, old_deposit) = x.take().ok_or(Error::<T>::NotFound)?;
903 let proxy_def = ProxyDefinition {
904 delegate: delegatee.clone(),
905 proxy_type: proxy_type.clone(),
906 delay,
907 };
908 let i = proxies.binary_search(&proxy_def).ok().ok_or(Error::<T>::NotFound)?;
909 proxies.remove(i);
910 let new_deposit = Self::deposit(proxies.len() as u32);
911 if new_deposit > old_deposit {
912 T::Currency::reserve(delegator, new_deposit - old_deposit)?;
913 } else if new_deposit < old_deposit {
914 T::Currency::unreserve(delegator, old_deposit - new_deposit);
915 }
916 if !proxies.is_empty() {
917 *x = Some((proxies, new_deposit))
918 }
919 Self::deposit_event(Event::<T>::ProxyRemoved {
920 delegator: delegator.clone(),
921 delegatee,
922 proxy_type,
923 delay,
924 });
925 Ok(())
926 })
927 }
928
929 pub fn deposit(num_proxies: u32) -> BalanceOf<T> {
930 if num_proxies == 0 {
931 Zero::zero()
932 } else {
933 T::ProxyDepositBase::get() + T::ProxyDepositFactor::get() * num_proxies.into()
934 }
935 }
936
937 fn rejig_deposit(
938 who: &T::AccountId,
939 old_deposit: BalanceOf<T>,
940 base: BalanceOf<T>,
941 factor: BalanceOf<T>,
942 len: usize,
943 ) -> Result<Option<BalanceOf<T>>, DispatchError> {
944 let new_deposit =
945 if len == 0 { BalanceOf::<T>::zero() } else { base + factor * (len as u32).into() };
946 if new_deposit > old_deposit {
947 T::Currency::reserve(who, new_deposit.saturating_sub(old_deposit))?;
948 } else if new_deposit < old_deposit {
949 let excess = old_deposit.saturating_sub(new_deposit);
950 let remaining_unreserved = T::Currency::unreserve(who, excess);
951 if !remaining_unreserved.is_zero() {
952 defensive!(
953 "Failed to unreserve full amount. (Requested, Actual)",
954 (excess, excess.saturating_sub(remaining_unreserved))
955 );
956 }
957 }
958 Ok(if len == 0 { None } else { Some(new_deposit) })
959 }
960
961 fn edit_announcements<
962 F: FnMut(&Announcement<T::AccountId, CallHashOf<T>, BlockNumberFor<T>>) -> bool,
963 >(
964 delegate: &T::AccountId,
965 f: F,
966 ) -> DispatchResult {
967 Announcements::<T>::try_mutate_exists(delegate, |x| {
968 let (mut pending, old_deposit) = x.take().ok_or(Error::<T>::NotFound)?;
969 let orig_pending_len = pending.len();
970 pending.retain(f);
971 ensure!(orig_pending_len > pending.len(), Error::<T>::NotFound);
972 *x = Self::rejig_deposit(
973 delegate,
974 old_deposit,
975 T::AnnouncementDepositBase::get(),
976 T::AnnouncementDepositFactor::get(),
977 pending.len(),
978 )?
979 .map(|deposit| (pending, deposit));
980 Ok(())
981 })
982 }
983
984 pub fn find_proxy(
985 real: &T::AccountId,
986 delegate: &T::AccountId,
987 force_proxy_type: Option<T::ProxyType>,
988 ) -> Result<ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>, DispatchError> {
989 let f = |x: &ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>| -> bool {
990 &x.delegate == delegate
991 && force_proxy_type.as_ref().map_or(true, |y| &x.proxy_type == y)
992 };
993 Ok(Proxies::<T>::get(real).0.into_iter().find(f).ok_or(Error::<T>::NotProxy)?)
994 }
995
996 fn do_proxy(
997 def: ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>,
998 real: T::AccountId,
999 call: <T as Config>::RuntimeCall,
1000 ) {
1001 use frame::traits::{InstanceFilter as _, OriginTrait as _};
1002 let mut origin: T::RuntimeOrigin = pezframe_system::RawOrigin::Signed(real).into();
1004 origin.add_filter(move |c: &<T as pezframe_system::Config>::RuntimeCall| {
1005 let c = <T as Config>::RuntimeCall::from_ref(c);
1006 match c.is_sub_type() {
1008 Some(Call::add_proxy { ref proxy_type, .. })
1011 | Some(Call::remove_proxy { ref proxy_type, .. })
1012 if !def.proxy_type.is_superset(proxy_type) =>
1013 {
1014 false
1015 },
1016 Some(Call::remove_proxies { .. }) | Some(Call::kill_pure { .. })
1019 if def.proxy_type != T::ProxyType::default() =>
1020 {
1021 false
1022 },
1023 _ => def.proxy_type.filter(c),
1024 }
1025 });
1026 let e = call.dispatch(origin);
1027 Self::deposit_event(Event::ProxyExecuted { result: e.map(|_| ()).map_err(|e| e.error) });
1028 }
1029
1030 pub fn remove_all_proxy_delegates(delegator: &T::AccountId) {
1035 let (proxies, old_deposit) = Proxies::<T>::take(delegator);
1036 T::Currency::unreserve(delegator, old_deposit);
1037 proxies.into_iter().for_each(|proxy_def| {
1038 Self::deposit_event(Event::<T>::ProxyRemoved {
1039 delegator: delegator.clone(),
1040 delegatee: proxy_def.delegate,
1041 proxy_type: proxy_def.proxy_type,
1042 delay: proxy_def.delay,
1043 });
1044 });
1045 }
1046}