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 pallet::*;
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 frame_system::Config>::AccountId>>::Balance;
49
50pub type BlockNumberFor<T> =
51 <<T as Config>::BlockNumberProvider as BlockNumberProvider>::BlockNumber;
52
53type AccountIdLookupOf<T> = <<T as frame_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::pallet]
124pub mod pallet {
125 use super::*;
126
127 #[pallet::pallet]
128 pub struct Pallet<T>(_);
129
130 #[pallet::config]
132 pub trait Config: frame_system::Config {
133 #[allow(deprecated)]
135 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
136
137 type RuntimeCall: Parameter
139 + Dispatchable<RuntimeOrigin = Self::RuntimeOrigin>
140 + GetDispatchInfo
141 + From<frame_system::Call<Self>>
142 + IsSubType<Call<Self>>
143 + IsType<<Self as frame_system::Config>::RuntimeCall>;
144
145 type Currency: ReservableCurrency<Self::AccountId>;
147
148 type ProxyType: Parameter
153 + Member
154 + Ord
155 + PartialOrd
156 + frame::traits::InstanceFilter<<Self as Config>::RuntimeCall>
157 + Default
158 + MaxEncodedLen;
159
160 #[pallet::constant]
165 type ProxyDepositBase: Get<BalanceOf<Self>>;
166
167 #[pallet::constant]
173 type ProxyDepositFactor: Get<BalanceOf<Self>>;
174
175 #[pallet::constant]
177 type MaxProxies: Get<u32>;
178
179 type WeightInfo: WeightInfo;
181
182 #[pallet::constant]
184 type MaxPending: Get<u32>;
185
186 type CallHasher: Hash;
188
189 #[pallet::constant]
194 type AnnouncementDepositBase: Get<BalanceOf<Self>>;
195
196 #[pallet::constant]
201 type AnnouncementDepositFactor: Get<BalanceOf<Self>>;
202
203 type BlockNumberProvider: BlockNumberProvider;
226 }
227
228 #[pallet::call]
229 impl<T: Config> Pallet<T> {
230 #[pallet::call_index(0)]
240 #[pallet::weight({
241 let di = call.get_dispatch_info();
242 (T::WeightInfo::proxy(T::MaxProxies::get())
243 .saturating_add(T::DbWeight::get().reads_writes(1, 1))
245 .saturating_add(di.call_weight),
246 di.class)
247 })]
248 pub fn proxy(
249 origin: OriginFor<T>,
250 real: AccountIdLookupOf<T>,
251 force_proxy_type: Option<T::ProxyType>,
252 call: Box<<T as Config>::RuntimeCall>,
253 ) -> DispatchResult {
254 let who = ensure_signed(origin)?;
255 let real = T::Lookup::lookup(real)?;
256 let def = Self::find_proxy(&real, &who, force_proxy_type)?;
257 ensure!(def.delay.is_zero(), Error::<T>::Unannounced);
258
259 Self::do_proxy(def, real, *call);
260
261 Ok(())
262 }
263
264 #[pallet::call_index(1)]
274 #[pallet::weight(T::WeightInfo::add_proxy(T::MaxProxies::get()))]
275 pub fn add_proxy(
276 origin: OriginFor<T>,
277 delegate: AccountIdLookupOf<T>,
278 proxy_type: T::ProxyType,
279 delay: BlockNumberFor<T>,
280 ) -> DispatchResult {
281 let who = ensure_signed(origin)?;
282 let delegate = T::Lookup::lookup(delegate)?;
283 Self::add_proxy_delegate(&who, delegate, proxy_type, delay)
284 }
285
286 #[pallet::call_index(2)]
294 #[pallet::weight(T::WeightInfo::remove_proxy(T::MaxProxies::get()))]
295 pub fn remove_proxy(
296 origin: OriginFor<T>,
297 delegate: AccountIdLookupOf<T>,
298 proxy_type: T::ProxyType,
299 delay: BlockNumberFor<T>,
300 ) -> DispatchResult {
301 let who = ensure_signed(origin)?;
302 let delegate = T::Lookup::lookup(delegate)?;
303 Self::remove_proxy_delegate(&who, delegate, proxy_type, delay)
304 }
305
306 #[pallet::call_index(3)]
313 #[pallet::weight(T::WeightInfo::remove_proxies(T::MaxProxies::get()))]
314 pub fn remove_proxies(origin: OriginFor<T>) -> DispatchResult {
315 let who = ensure_signed(origin)?;
316 Self::remove_all_proxy_delegates(&who);
317 Ok(())
318 }
319
320 #[pallet::call_index(4)]
339 #[pallet::weight(T::WeightInfo::create_pure(T::MaxProxies::get()))]
340 pub fn create_pure(
341 origin: OriginFor<T>,
342 proxy_type: T::ProxyType,
343 delay: BlockNumberFor<T>,
344 index: u16,
345 ) -> DispatchResult {
346 let who = ensure_signed(origin)?;
347
348 let pure = Self::pure_account(&who, &proxy_type, index, None);
349 ensure!(!Proxies::<T>::contains_key(&pure), Error::<T>::Duplicate);
350
351 let proxy_def =
352 ProxyDefinition { delegate: who.clone(), proxy_type: proxy_type.clone(), delay };
353 let bounded_proxies: BoundedVec<_, T::MaxProxies> =
354 vec![proxy_def].try_into().map_err(|_| Error::<T>::TooMany)?;
355
356 let deposit = T::ProxyDepositBase::get() + T::ProxyDepositFactor::get();
357 T::Currency::reserve(&who, deposit)?;
358
359 Proxies::<T>::insert(&pure, (bounded_proxies, deposit));
360 let extrinsic_index = <frame_system::Pallet<T>>::extrinsic_index().unwrap_or_default();
361 Self::deposit_event(Event::PureCreated {
362 pure,
363 who,
364 proxy_type,
365 disambiguation_index: index,
366 at: T::BlockNumberProvider::current_block_number(),
367 extrinsic_index,
368 });
369
370 Ok(())
371 }
372
373 #[pallet::call_index(5)]
390 #[pallet::weight(T::WeightInfo::kill_pure(T::MaxProxies::get()))]
391 pub fn kill_pure(
392 origin: OriginFor<T>,
393 spawner: AccountIdLookupOf<T>,
394 proxy_type: T::ProxyType,
395 index: u16,
396 #[pallet::compact] height: BlockNumberFor<T>,
397 #[pallet::compact] ext_index: u32,
398 ) -> DispatchResult {
399 let who = ensure_signed(origin)?;
400 let spawner = T::Lookup::lookup(spawner)?;
401
402 let when = (height, ext_index);
403 let proxy = Self::pure_account(&spawner, &proxy_type, index, Some(when));
404 ensure!(proxy == who, Error::<T>::NoPermission);
405
406 let (_, deposit) = Proxies::<T>::take(&who);
407 T::Currency::unreserve(&spawner, deposit);
408
409 Self::deposit_event(Event::PureKilled {
410 pure: who,
411 spawner,
412 proxy_type,
413 disambiguation_index: index,
414 });
415
416 Ok(())
417 }
418
419 #[pallet::call_index(6)]
435 #[pallet::weight(T::WeightInfo::announce(T::MaxPending::get(), T::MaxProxies::get()))]
436 pub fn announce(
437 origin: OriginFor<T>,
438 real: AccountIdLookupOf<T>,
439 call_hash: CallHashOf<T>,
440 ) -> DispatchResult {
441 let who = ensure_signed(origin)?;
442 let real = T::Lookup::lookup(real)?;
443 Proxies::<T>::get(&real)
444 .0
445 .into_iter()
446 .find(|x| x.delegate == who)
447 .ok_or(Error::<T>::NotProxy)?;
448
449 let announcement = Announcement {
450 real: real.clone(),
451 call_hash,
452 height: T::BlockNumberProvider::current_block_number(),
453 };
454
455 Announcements::<T>::try_mutate(&who, |(ref mut pending, ref mut deposit)| {
456 pending.try_push(announcement).map_err(|_| Error::<T>::TooMany)?;
457 Self::rejig_deposit(
458 &who,
459 *deposit,
460 T::AnnouncementDepositBase::get(),
461 T::AnnouncementDepositFactor::get(),
462 pending.len(),
463 )
464 .map(|d| {
465 d.expect("Just pushed; pending.len() > 0; rejig_deposit returns Some; qed")
466 })
467 .map(|d| *deposit = d)
468 })?;
469 Self::deposit_event(Event::Announced { real, proxy: who, call_hash });
470
471 Ok(())
472 }
473
474 #[pallet::call_index(7)]
485 #[pallet::weight(T::WeightInfo::remove_announcement(
486 T::MaxPending::get(),
487 T::MaxProxies::get()
488 ))]
489 pub fn remove_announcement(
490 origin: OriginFor<T>,
491 real: AccountIdLookupOf<T>,
492 call_hash: CallHashOf<T>,
493 ) -> DispatchResult {
494 let who = ensure_signed(origin)?;
495 let real = T::Lookup::lookup(real)?;
496 Self::edit_announcements(&who, |ann| ann.real != real || ann.call_hash != call_hash)?;
497
498 Ok(())
499 }
500
501 #[pallet::call_index(8)]
512 #[pallet::weight(T::WeightInfo::reject_announcement(
513 T::MaxPending::get(),
514 T::MaxProxies::get()
515 ))]
516 pub fn reject_announcement(
517 origin: OriginFor<T>,
518 delegate: AccountIdLookupOf<T>,
519 call_hash: CallHashOf<T>,
520 ) -> DispatchResult {
521 let who = ensure_signed(origin)?;
522 let delegate = T::Lookup::lookup(delegate)?;
523 Self::edit_announcements(&delegate, |ann| {
524 ann.real != who || ann.call_hash != call_hash
525 })?;
526
527 Ok(())
528 }
529
530 #[pallet::call_index(9)]
542 #[pallet::weight({
543 let di = call.get_dispatch_info();
544 (T::WeightInfo::proxy_announced(T::MaxPending::get(), T::MaxProxies::get())
545 .saturating_add(T::DbWeight::get().reads_writes(1, 1))
547 .saturating_add(di.call_weight),
548 di.class)
549 })]
550 pub fn proxy_announced(
551 origin: OriginFor<T>,
552 delegate: AccountIdLookupOf<T>,
553 real: AccountIdLookupOf<T>,
554 force_proxy_type: Option<T::ProxyType>,
555 call: Box<<T as Config>::RuntimeCall>,
556 ) -> DispatchResult {
557 ensure_signed(origin)?;
558 let delegate = T::Lookup::lookup(delegate)?;
559 let real = T::Lookup::lookup(real)?;
560 let def = Self::find_proxy(&real, &delegate, force_proxy_type)?;
561
562 let call_hash = T::CallHasher::hash_of(&call);
563 let now = T::BlockNumberProvider::current_block_number();
564 Self::edit_announcements(&delegate, |ann| {
565 ann.real != real ||
566 ann.call_hash != call_hash ||
567 now.saturating_sub(ann.height) < def.delay
568 })
569 .map_err(|_| Error::<T>::Unannounced)?;
570
571 Self::do_proxy(def, real, *call);
572
573 Ok(())
574 }
575
576 #[pallet::call_index(10)]
585 #[pallet::weight(T::WeightInfo::poke_deposit())]
586 pub fn poke_deposit(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
587 let who = ensure_signed(origin)?;
588 let mut deposit_updated = false;
589
590 Proxies::<T>::try_mutate_exists(&who, |maybe_proxies| -> DispatchResult {
592 let (proxies, old_deposit) = maybe_proxies.take().unwrap_or_default();
593 let maybe_new_deposit = Self::rejig_deposit(
594 &who,
595 old_deposit,
596 T::ProxyDepositBase::get(),
597 T::ProxyDepositFactor::get(),
598 proxies.len(),
599 )?;
600
601 match maybe_new_deposit {
602 Some(new_deposit) if new_deposit != old_deposit => {
603 *maybe_proxies = Some((proxies, new_deposit));
604 deposit_updated = true;
605 Self::deposit_event(Event::DepositPoked {
606 who: who.clone(),
607 kind: DepositKind::Proxies,
608 old_deposit,
609 new_deposit,
610 });
611 },
612 Some(_) => {
613 *maybe_proxies = Some((proxies, old_deposit));
614 },
615 None => {
616 *maybe_proxies = None;
617 if !old_deposit.is_zero() {
618 deposit_updated = true;
619 Self::deposit_event(Event::DepositPoked {
620 who: who.clone(),
621 kind: DepositKind::Proxies,
622 old_deposit,
623 new_deposit: BalanceOf::<T>::zero(),
624 });
625 }
626 },
627 }
628 Ok(())
629 })?;
630
631 Announcements::<T>::try_mutate_exists(&who, |maybe_announcements| -> DispatchResult {
633 let (announcements, old_deposit) = maybe_announcements.take().unwrap_or_default();
634 let maybe_new_deposit = Self::rejig_deposit(
635 &who,
636 old_deposit,
637 T::AnnouncementDepositBase::get(),
638 T::AnnouncementDepositFactor::get(),
639 announcements.len(),
640 )?;
641
642 match maybe_new_deposit {
643 Some(new_deposit) if new_deposit != old_deposit => {
644 *maybe_announcements = Some((announcements, new_deposit));
645 deposit_updated = true;
646 Self::deposit_event(Event::DepositPoked {
647 who: who.clone(),
648 kind: DepositKind::Announcements,
649 old_deposit,
650 new_deposit,
651 });
652 },
653 Some(_) => {
654 *maybe_announcements = Some((announcements, old_deposit));
655 },
656 None => {
657 *maybe_announcements = None;
658 if !old_deposit.is_zero() {
659 deposit_updated = true;
660 Self::deposit_event(Event::DepositPoked {
661 who: who.clone(),
662 kind: DepositKind::Announcements,
663 old_deposit,
664 new_deposit: BalanceOf::<T>::zero(),
665 });
666 }
667 },
668 }
669 Ok(())
670 })?;
671
672 Ok(if deposit_updated { Pays::No.into() } else { Pays::Yes.into() })
673 }
674 }
675
676 #[pallet::event]
677 #[pallet::generate_deposit(pub(super) fn deposit_event)]
678 pub enum Event<T: Config> {
679 ProxyExecuted { result: DispatchResult },
681 PureCreated {
684 pure: T::AccountId,
685 who: T::AccountId,
686 proxy_type: T::ProxyType,
687 disambiguation_index: u16,
688 at: BlockNumberFor<T>,
689 extrinsic_index: u32,
690 },
691 PureKilled {
693 pure: T::AccountId,
695 spawner: T::AccountId,
697 proxy_type: T::ProxyType,
699 disambiguation_index: u16,
701 },
702 Announced { real: T::AccountId, proxy: T::AccountId, call_hash: CallHashOf<T> },
704 ProxyAdded {
706 delegator: T::AccountId,
707 delegatee: T::AccountId,
708 proxy_type: T::ProxyType,
709 delay: BlockNumberFor<T>,
710 },
711 ProxyRemoved {
713 delegator: T::AccountId,
714 delegatee: T::AccountId,
715 proxy_type: T::ProxyType,
716 delay: BlockNumberFor<T>,
717 },
718 DepositPoked {
720 who: T::AccountId,
721 kind: DepositKind,
722 old_deposit: BalanceOf<T>,
723 new_deposit: BalanceOf<T>,
724 },
725 }
726
727 #[pallet::error]
728 pub enum Error<T> {
729 TooMany,
731 NotFound,
733 NotProxy,
735 Unproxyable,
737 Duplicate,
739 NoPermission,
741 Unannounced,
743 NoSelfProxy,
745 }
746
747 #[pallet::storage]
750 pub type Proxies<T: Config> = StorageMap<
751 _,
752 Twox64Concat,
753 T::AccountId,
754 (
755 BoundedVec<
756 ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>,
757 T::MaxProxies,
758 >,
759 BalanceOf<T>,
760 ),
761 ValueQuery,
762 >;
763
764 #[pallet::storage]
766 pub type Announcements<T: Config> = StorageMap<
767 _,
768 Twox64Concat,
769 T::AccountId,
770 (
771 BoundedVec<Announcement<T::AccountId, CallHashOf<T>, BlockNumberFor<T>>, T::MaxPending>,
772 BalanceOf<T>,
773 ),
774 ValueQuery,
775 >;
776
777 #[pallet::view_functions]
778 impl<T: Config> Pallet<T> {
779 pub fn check_permissions(
781 call: <T as Config>::RuntimeCall,
782 proxy_type: T::ProxyType,
783 ) -> bool {
784 proxy_type.filter(&call)
785 }
786
787 pub fn is_superset(to_check: T::ProxyType, against: T::ProxyType) -> bool {
789 to_check.is_superset(&against)
790 }
791 }
792}
793
794impl<T: Config> Pallet<T> {
795 pub fn proxies(
797 account: T::AccountId,
798 ) -> (
799 BoundedVec<ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>, T::MaxProxies>,
800 BalanceOf<T>,
801 ) {
802 Proxies::<T>::get(account)
803 }
804
805 pub fn announcements(
807 account: T::AccountId,
808 ) -> (
809 BoundedVec<Announcement<T::AccountId, CallHashOf<T>, BlockNumberFor<T>>, T::MaxPending>,
810 BalanceOf<T>,
811 ) {
812 Announcements::<T>::get(account)
813 }
814
815 pub fn pure_account(
827 who: &T::AccountId,
828 proxy_type: &T::ProxyType,
829 index: u16,
830 maybe_when: Option<(BlockNumberFor<T>, u32)>,
831 ) -> T::AccountId {
832 let (height, ext_index) = maybe_when.unwrap_or_else(|| {
833 (
834 T::BlockNumberProvider::current_block_number(),
835 frame_system::Pallet::<T>::extrinsic_index().unwrap_or_default(),
836 )
837 });
838
839 let entropy = (b"modlpy/proxy____", who, height, ext_index, proxy_type, index)
840 .using_encoded(blake2_256);
841 Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref()))
842 .expect("infinite length input; no invalid inputs for type; qed")
843 }
844
845 pub fn add_proxy_delegate(
854 delegator: &T::AccountId,
855 delegatee: T::AccountId,
856 proxy_type: T::ProxyType,
857 delay: BlockNumberFor<T>,
858 ) -> DispatchResult {
859 ensure!(delegator != &delegatee, Error::<T>::NoSelfProxy);
860 Proxies::<T>::try_mutate(delegator, |(ref mut proxies, ref mut deposit)| {
861 let proxy_def = ProxyDefinition {
862 delegate: delegatee.clone(),
863 proxy_type: proxy_type.clone(),
864 delay,
865 };
866 let i = proxies.binary_search(&proxy_def).err().ok_or(Error::<T>::Duplicate)?;
867 proxies.try_insert(i, proxy_def).map_err(|_| Error::<T>::TooMany)?;
868 let new_deposit = Self::deposit(proxies.len() as u32);
869 if new_deposit > *deposit {
870 T::Currency::reserve(delegator, new_deposit - *deposit)?;
871 } else if new_deposit < *deposit {
872 T::Currency::unreserve(delegator, *deposit - new_deposit);
873 }
874 *deposit = new_deposit;
875 Self::deposit_event(Event::<T>::ProxyAdded {
876 delegator: delegator.clone(),
877 delegatee,
878 proxy_type,
879 delay,
880 });
881 Ok(())
882 })
883 }
884
885 pub fn remove_proxy_delegate(
894 delegator: &T::AccountId,
895 delegatee: T::AccountId,
896 proxy_type: T::ProxyType,
897 delay: BlockNumberFor<T>,
898 ) -> DispatchResult {
899 Proxies::<T>::try_mutate_exists(delegator, |x| {
900 let (mut proxies, old_deposit) = x.take().ok_or(Error::<T>::NotFound)?;
901 let proxy_def = ProxyDefinition {
902 delegate: delegatee.clone(),
903 proxy_type: proxy_type.clone(),
904 delay,
905 };
906 let i = proxies.binary_search(&proxy_def).ok().ok_or(Error::<T>::NotFound)?;
907 proxies.remove(i);
908 let new_deposit = Self::deposit(proxies.len() as u32);
909 if new_deposit > old_deposit {
910 T::Currency::reserve(delegator, new_deposit - old_deposit)?;
911 } else if new_deposit < old_deposit {
912 T::Currency::unreserve(delegator, old_deposit - new_deposit);
913 }
914 if !proxies.is_empty() {
915 *x = Some((proxies, new_deposit))
916 }
917 Self::deposit_event(Event::<T>::ProxyRemoved {
918 delegator: delegator.clone(),
919 delegatee,
920 proxy_type,
921 delay,
922 });
923 Ok(())
924 })
925 }
926
927 pub fn deposit(num_proxies: u32) -> BalanceOf<T> {
928 if num_proxies == 0 {
929 Zero::zero()
930 } else {
931 T::ProxyDepositBase::get() + T::ProxyDepositFactor::get() * num_proxies.into()
932 }
933 }
934
935 fn rejig_deposit(
936 who: &T::AccountId,
937 old_deposit: BalanceOf<T>,
938 base: BalanceOf<T>,
939 factor: BalanceOf<T>,
940 len: usize,
941 ) -> Result<Option<BalanceOf<T>>, DispatchError> {
942 let new_deposit =
943 if len == 0 { BalanceOf::<T>::zero() } else { base + factor * (len as u32).into() };
944 if new_deposit > old_deposit {
945 T::Currency::reserve(who, new_deposit.saturating_sub(old_deposit))?;
946 } else if new_deposit < old_deposit {
947 let excess = old_deposit.saturating_sub(new_deposit);
948 let remaining_unreserved = T::Currency::unreserve(who, excess);
949 if !remaining_unreserved.is_zero() {
950 defensive!(
951 "Failed to unreserve full amount. (Requested, Actual)",
952 (excess, excess.saturating_sub(remaining_unreserved))
953 );
954 }
955 }
956 Ok(if len == 0 { None } else { Some(new_deposit) })
957 }
958
959 fn edit_announcements<
960 F: FnMut(&Announcement<T::AccountId, CallHashOf<T>, BlockNumberFor<T>>) -> bool,
961 >(
962 delegate: &T::AccountId,
963 f: F,
964 ) -> DispatchResult {
965 Announcements::<T>::try_mutate_exists(delegate, |x| {
966 let (mut pending, old_deposit) = x.take().ok_or(Error::<T>::NotFound)?;
967 let orig_pending_len = pending.len();
968 pending.retain(f);
969 ensure!(orig_pending_len > pending.len(), Error::<T>::NotFound);
970 *x = Self::rejig_deposit(
971 delegate,
972 old_deposit,
973 T::AnnouncementDepositBase::get(),
974 T::AnnouncementDepositFactor::get(),
975 pending.len(),
976 )?
977 .map(|deposit| (pending, deposit));
978 Ok(())
979 })
980 }
981
982 pub fn find_proxy(
983 real: &T::AccountId,
984 delegate: &T::AccountId,
985 force_proxy_type: Option<T::ProxyType>,
986 ) -> Result<ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>, DispatchError> {
987 let f = |x: &ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>| -> bool {
988 &x.delegate == delegate &&
989 force_proxy_type.as_ref().map_or(true, |y| &x.proxy_type == y)
990 };
991 Ok(Proxies::<T>::get(real).0.into_iter().find(f).ok_or(Error::<T>::NotProxy)?)
992 }
993
994 fn do_proxy(
995 def: ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>,
996 real: T::AccountId,
997 call: <T as Config>::RuntimeCall,
998 ) {
999 use frame::traits::{InstanceFilter as _, OriginTrait as _};
1000 let mut origin: T::RuntimeOrigin = frame_system::RawOrigin::Signed(real).into();
1002 origin.add_filter(move |c: &<T as frame_system::Config>::RuntimeCall| {
1003 let c = <T as Config>::RuntimeCall::from_ref(c);
1004 match c.is_sub_type() {
1006 Some(Call::add_proxy { ref proxy_type, .. }) |
1009 Some(Call::remove_proxy { ref proxy_type, .. })
1010 if !def.proxy_type.is_superset(proxy_type) =>
1011 false,
1012 Some(Call::remove_proxies { .. }) | Some(Call::kill_pure { .. })
1015 if def.proxy_type != T::ProxyType::default() =>
1016 false,
1017 _ => def.proxy_type.filter(c),
1018 }
1019 });
1020 let e = call.dispatch(origin);
1021 Self::deposit_event(Event::ProxyExecuted { result: e.map(|_| ()).map_err(|e| e.error) });
1022 }
1023
1024 pub fn remove_all_proxy_delegates(delegator: &T::AccountId) {
1029 let (_, old_deposit) = Proxies::<T>::take(&delegator);
1030 T::Currency::unreserve(&delegator, old_deposit);
1031 }
1032}