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 Debug,
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 Debug,
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 Debug,
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, PostInfo = PostDispatchInfo>
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 (Pallet::<T>::proxy_weight(di.call_weight), di.class)
243 })]
244 pub fn proxy(
245 origin: OriginFor<T>,
246 real: AccountIdLookupOf<T>,
247 force_proxy_type: Option<T::ProxyType>,
248 call: Box<<T as Config>::RuntimeCall>,
249 ) -> DispatchResultWithPostInfo {
250 let who = ensure_signed(origin)?;
251 let real = T::Lookup::lookup(real)?;
252 let def = Self::find_proxy(&real, &who, force_proxy_type)?;
253 ensure!(def.delay.is_zero(), Error::<T>::Unannounced);
254
255 let result = Self::do_proxy(def, real, *call);
256
257 Ok(get_result_weight(result).map(Self::proxy_weight).into())
258 }
259
260 #[pallet::call_index(1)]
270 #[pallet::weight(T::WeightInfo::add_proxy(T::MaxProxies::get()))]
271 pub fn add_proxy(
272 origin: OriginFor<T>,
273 delegate: AccountIdLookupOf<T>,
274 proxy_type: T::ProxyType,
275 delay: BlockNumberFor<T>,
276 ) -> DispatchResult {
277 let who = ensure_signed(origin)?;
278 let delegate = T::Lookup::lookup(delegate)?;
279 Self::add_proxy_delegate(&who, delegate, proxy_type, delay)
280 }
281
282 #[pallet::call_index(2)]
290 #[pallet::weight(T::WeightInfo::remove_proxy(T::MaxProxies::get()))]
291 pub fn remove_proxy(
292 origin: OriginFor<T>,
293 delegate: AccountIdLookupOf<T>,
294 proxy_type: T::ProxyType,
295 delay: BlockNumberFor<T>,
296 ) -> DispatchResult {
297 let who = ensure_signed(origin)?;
298 let delegate = T::Lookup::lookup(delegate)?;
299 Self::remove_proxy_delegate(&who, delegate, proxy_type, delay)
300 }
301
302 #[pallet::call_index(3)]
309 #[pallet::weight(T::WeightInfo::remove_proxies(T::MaxProxies::get()))]
310 pub fn remove_proxies(origin: OriginFor<T>) -> DispatchResult {
311 let who = ensure_signed(origin)?;
312 Self::remove_all_proxy_delegates(&who);
313 Ok(())
314 }
315
316 #[pallet::call_index(4)]
335 #[pallet::weight(T::WeightInfo::create_pure(T::MaxProxies::get()))]
336 pub fn create_pure(
337 origin: OriginFor<T>,
338 proxy_type: T::ProxyType,
339 delay: BlockNumberFor<T>,
340 index: u16,
341 ) -> DispatchResult {
342 let who = ensure_signed(origin)?;
343
344 let pure = Self::pure_account(&who, &proxy_type, index, None);
345 ensure!(!Proxies::<T>::contains_key(&pure), Error::<T>::Duplicate);
346
347 let proxy_def =
348 ProxyDefinition { delegate: who.clone(), proxy_type: proxy_type.clone(), delay };
349 let bounded_proxies: BoundedVec<_, T::MaxProxies> =
350 vec![proxy_def].try_into().map_err(|_| Error::<T>::TooMany)?;
351
352 let deposit = T::ProxyDepositBase::get() + T::ProxyDepositFactor::get();
353 T::Currency::reserve(&who, deposit)?;
354
355 Proxies::<T>::insert(&pure, (bounded_proxies, deposit));
356 let extrinsic_index = <frame_system::Pallet<T>>::extrinsic_index().unwrap_or_default();
357 Self::deposit_event(Event::PureCreated {
358 pure,
359 who,
360 proxy_type,
361 disambiguation_index: index,
362 at: T::BlockNumberProvider::current_block_number(),
363 extrinsic_index,
364 });
365
366 Ok(())
367 }
368
369 #[pallet::call_index(5)]
386 #[pallet::weight(T::WeightInfo::kill_pure(T::MaxProxies::get()))]
387 pub fn kill_pure(
388 origin: OriginFor<T>,
389 spawner: AccountIdLookupOf<T>,
390 proxy_type: T::ProxyType,
391 index: u16,
392 #[pallet::compact] height: BlockNumberFor<T>,
393 #[pallet::compact] ext_index: u32,
394 ) -> DispatchResult {
395 let who = ensure_signed(origin)?;
396 let spawner = T::Lookup::lookup(spawner)?;
397
398 let when = (height, ext_index);
399 let proxy = Self::pure_account(&spawner, &proxy_type, index, Some(when));
400 ensure!(proxy == who, Error::<T>::NoPermission);
401
402 let (_, deposit) = Proxies::<T>::take(&who);
403 T::Currency::unreserve(&spawner, deposit);
404
405 Self::deposit_event(Event::PureKilled {
406 pure: who,
407 spawner,
408 proxy_type,
409 disambiguation_index: index,
410 });
411
412 Ok(())
413 }
414
415 #[pallet::call_index(6)]
431 #[pallet::weight(T::WeightInfo::announce(T::MaxPending::get(), T::MaxProxies::get()))]
432 pub fn announce(
433 origin: OriginFor<T>,
434 real: AccountIdLookupOf<T>,
435 call_hash: CallHashOf<T>,
436 ) -> DispatchResult {
437 let who = ensure_signed(origin)?;
438 let real = T::Lookup::lookup(real)?;
439 Proxies::<T>::get(&real)
440 .0
441 .into_iter()
442 .find(|x| x.delegate == who)
443 .ok_or(Error::<T>::NotProxy)?;
444
445 let announcement = Announcement {
446 real: real.clone(),
447 call_hash,
448 height: T::BlockNumberProvider::current_block_number(),
449 };
450
451 Announcements::<T>::try_mutate(&who, |(ref mut pending, ref mut deposit)| {
452 pending.try_push(announcement).map_err(|_| Error::<T>::TooMany)?;
453 Self::rejig_deposit(
454 &who,
455 *deposit,
456 T::AnnouncementDepositBase::get(),
457 T::AnnouncementDepositFactor::get(),
458 pending.len(),
459 )
460 .map(|d| {
461 d.expect("Just pushed; pending.len() > 0; rejig_deposit returns Some; qed")
462 })
463 .map(|d| *deposit = d)
464 })?;
465 Self::deposit_event(Event::Announced { real, proxy: who, call_hash });
466
467 Ok(())
468 }
469
470 #[pallet::call_index(7)]
481 #[pallet::weight(T::WeightInfo::remove_announcement(
482 T::MaxPending::get(),
483 T::MaxProxies::get()
484 ))]
485 pub fn remove_announcement(
486 origin: OriginFor<T>,
487 real: AccountIdLookupOf<T>,
488 call_hash: CallHashOf<T>,
489 ) -> DispatchResult {
490 let who = ensure_signed(origin)?;
491 let real = T::Lookup::lookup(real)?;
492 Self::edit_announcements(&who, |ann| ann.real != real || ann.call_hash != call_hash)?;
493
494 Ok(())
495 }
496
497 #[pallet::call_index(8)]
508 #[pallet::weight(T::WeightInfo::reject_announcement(
509 T::MaxPending::get(),
510 T::MaxProxies::get()
511 ))]
512 pub fn reject_announcement(
513 origin: OriginFor<T>,
514 delegate: AccountIdLookupOf<T>,
515 call_hash: CallHashOf<T>,
516 ) -> DispatchResult {
517 let who = ensure_signed(origin)?;
518 let delegate = T::Lookup::lookup(delegate)?;
519 Self::edit_announcements(&delegate, |ann| {
520 ann.real != who || ann.call_hash != call_hash
521 })?;
522
523 Ok(())
524 }
525
526 #[pallet::call_index(9)]
538 #[pallet::weight({
539 let di = call.get_dispatch_info();
540 (Pallet::<T>::proxy_announced_weight(di.call_weight), di.class)
541 })]
542 pub fn proxy_announced(
543 origin: OriginFor<T>,
544 delegate: AccountIdLookupOf<T>,
545 real: AccountIdLookupOf<T>,
546 force_proxy_type: Option<T::ProxyType>,
547 call: Box<<T as Config>::RuntimeCall>,
548 ) -> DispatchResultWithPostInfo {
549 ensure_signed(origin)?;
550 let delegate = T::Lookup::lookup(delegate)?;
551 let real = T::Lookup::lookup(real)?;
552 let def = Self::find_proxy(&real, &delegate, force_proxy_type)?;
553
554 let call_hash = T::CallHasher::hash_of(&call);
555 let now = T::BlockNumberProvider::current_block_number();
556 Self::edit_announcements(&delegate, |ann| {
557 ann.real != real ||
558 ann.call_hash != call_hash ||
559 now.saturating_sub(ann.height) < def.delay
560 })
561 .map_err(|_| Error::<T>::Unannounced)?;
562
563 let result = Self::do_proxy(def, real, *call);
564
565 Ok(get_result_weight(result).map(Self::proxy_announced_weight).into())
566 }
567
568 #[pallet::call_index(10)]
577 #[pallet::weight(T::WeightInfo::poke_deposit())]
578 pub fn poke_deposit(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
579 let who = ensure_signed(origin)?;
580 let mut deposit_updated = false;
581
582 Proxies::<T>::try_mutate_exists(&who, |maybe_proxies| -> DispatchResult {
584 let (proxies, old_deposit) = maybe_proxies.take().unwrap_or_default();
585 let maybe_new_deposit = Self::rejig_deposit(
586 &who,
587 old_deposit,
588 T::ProxyDepositBase::get(),
589 T::ProxyDepositFactor::get(),
590 proxies.len(),
591 )?;
592
593 match maybe_new_deposit {
594 Some(new_deposit) if new_deposit != old_deposit => {
595 *maybe_proxies = Some((proxies, new_deposit));
596 deposit_updated = true;
597 Self::deposit_event(Event::DepositPoked {
598 who: who.clone(),
599 kind: DepositKind::Proxies,
600 old_deposit,
601 new_deposit,
602 });
603 },
604 Some(_) => {
605 *maybe_proxies = Some((proxies, old_deposit));
606 },
607 None => {
608 *maybe_proxies = None;
609 if !old_deposit.is_zero() {
610 deposit_updated = true;
611 Self::deposit_event(Event::DepositPoked {
612 who: who.clone(),
613 kind: DepositKind::Proxies,
614 old_deposit,
615 new_deposit: BalanceOf::<T>::zero(),
616 });
617 }
618 },
619 }
620 Ok(())
621 })?;
622
623 Announcements::<T>::try_mutate_exists(&who, |maybe_announcements| -> DispatchResult {
625 let (announcements, old_deposit) = maybe_announcements.take().unwrap_or_default();
626 let maybe_new_deposit = Self::rejig_deposit(
627 &who,
628 old_deposit,
629 T::AnnouncementDepositBase::get(),
630 T::AnnouncementDepositFactor::get(),
631 announcements.len(),
632 )?;
633
634 match maybe_new_deposit {
635 Some(new_deposit) if new_deposit != old_deposit => {
636 *maybe_announcements = Some((announcements, new_deposit));
637 deposit_updated = true;
638 Self::deposit_event(Event::DepositPoked {
639 who: who.clone(),
640 kind: DepositKind::Announcements,
641 old_deposit,
642 new_deposit,
643 });
644 },
645 Some(_) => {
646 *maybe_announcements = Some((announcements, old_deposit));
647 },
648 None => {
649 *maybe_announcements = None;
650 if !old_deposit.is_zero() {
651 deposit_updated = true;
652 Self::deposit_event(Event::DepositPoked {
653 who: who.clone(),
654 kind: DepositKind::Announcements,
655 old_deposit,
656 new_deposit: BalanceOf::<T>::zero(),
657 });
658 }
659 },
660 }
661 Ok(())
662 })?;
663
664 Ok(if deposit_updated { Pays::No.into() } else { Pays::Yes.into() })
665 }
666 }
667
668 #[pallet::event]
669 #[pallet::generate_deposit(pub(super) fn deposit_event)]
670 pub enum Event<T: Config> {
671 ProxyExecuted { result: DispatchResult },
673 PureCreated {
676 pure: T::AccountId,
677 who: T::AccountId,
678 proxy_type: T::ProxyType,
679 disambiguation_index: u16,
680 at: BlockNumberFor<T>,
681 extrinsic_index: u32,
682 },
683 PureKilled {
685 pure: T::AccountId,
687 spawner: T::AccountId,
689 proxy_type: T::ProxyType,
691 disambiguation_index: u16,
693 },
694 Announced { real: T::AccountId, proxy: T::AccountId, call_hash: CallHashOf<T> },
696 ProxyAdded {
698 delegator: T::AccountId,
699 delegatee: T::AccountId,
700 proxy_type: T::ProxyType,
701 delay: BlockNumberFor<T>,
702 },
703 ProxyRemoved {
705 delegator: T::AccountId,
706 delegatee: T::AccountId,
707 proxy_type: T::ProxyType,
708 delay: BlockNumberFor<T>,
709 },
710 DepositPoked {
712 who: T::AccountId,
713 kind: DepositKind,
714 old_deposit: BalanceOf<T>,
715 new_deposit: BalanceOf<T>,
716 },
717 }
718
719 #[pallet::error]
720 pub enum Error<T> {
721 TooMany,
723 NotFound,
725 NotProxy,
727 Unproxyable,
729 Duplicate,
731 NoPermission,
733 Unannounced,
735 NoSelfProxy,
737 }
738
739 #[pallet::storage]
742 pub type Proxies<T: Config> = StorageMap<
743 _,
744 Twox64Concat,
745 T::AccountId,
746 (
747 BoundedVec<
748 ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>,
749 T::MaxProxies,
750 >,
751 BalanceOf<T>,
752 ),
753 ValueQuery,
754 >;
755
756 #[pallet::storage]
758 pub type Announcements<T: Config> = StorageMap<
759 _,
760 Twox64Concat,
761 T::AccountId,
762 (
763 BoundedVec<Announcement<T::AccountId, CallHashOf<T>, BlockNumberFor<T>>, T::MaxPending>,
764 BalanceOf<T>,
765 ),
766 ValueQuery,
767 >;
768
769 #[pallet::view_functions]
770 impl<T: Config> Pallet<T> {
771 pub fn check_permissions(
773 call: <T as Config>::RuntimeCall,
774 proxy_type: T::ProxyType,
775 ) -> bool {
776 proxy_type.filter(&call)
777 }
778
779 pub fn is_superset(to_check: T::ProxyType, against: T::ProxyType) -> bool {
781 to_check.is_superset(&against)
782 }
783 }
784}
785
786impl<T: Config> Pallet<T> {
787 pub fn proxies(
789 account: T::AccountId,
790 ) -> (
791 BoundedVec<ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>, T::MaxProxies>,
792 BalanceOf<T>,
793 ) {
794 Proxies::<T>::get(account)
795 }
796
797 pub fn announcements(
799 account: T::AccountId,
800 ) -> (
801 BoundedVec<Announcement<T::AccountId, CallHashOf<T>, BlockNumberFor<T>>, T::MaxPending>,
802 BalanceOf<T>,
803 ) {
804 Announcements::<T>::get(account)
805 }
806
807 pub fn pure_account(
819 who: &T::AccountId,
820 proxy_type: &T::ProxyType,
821 index: u16,
822 maybe_when: Option<(BlockNumberFor<T>, u32)>,
823 ) -> T::AccountId {
824 let (height, ext_index) = maybe_when.unwrap_or_else(|| {
825 (
826 T::BlockNumberProvider::current_block_number(),
827 frame_system::Pallet::<T>::extrinsic_index().unwrap_or_default(),
828 )
829 });
830
831 let entropy = (b"modlpy/proxy____", who, height, ext_index, proxy_type, index)
832 .using_encoded(blake2_256);
833 Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref()))
834 .expect("infinite length input; no invalid inputs for type; qed")
835 }
836
837 pub fn add_proxy_delegate(
846 delegator: &T::AccountId,
847 delegatee: T::AccountId,
848 proxy_type: T::ProxyType,
849 delay: BlockNumberFor<T>,
850 ) -> DispatchResult {
851 ensure!(delegator != &delegatee, Error::<T>::NoSelfProxy);
852 Proxies::<T>::try_mutate(delegator, |(ref mut proxies, ref mut deposit)| {
853 let proxy_def = ProxyDefinition {
854 delegate: delegatee.clone(),
855 proxy_type: proxy_type.clone(),
856 delay,
857 };
858 let i = proxies.binary_search(&proxy_def).err().ok_or(Error::<T>::Duplicate)?;
859 proxies.try_insert(i, proxy_def).map_err(|_| Error::<T>::TooMany)?;
860 let new_deposit = Self::deposit(proxies.len() as u32);
861 if new_deposit > *deposit {
862 T::Currency::reserve(delegator, new_deposit - *deposit)?;
863 } else if new_deposit < *deposit {
864 T::Currency::unreserve(delegator, *deposit - new_deposit);
865 }
866 *deposit = new_deposit;
867 Self::deposit_event(Event::<T>::ProxyAdded {
868 delegator: delegator.clone(),
869 delegatee,
870 proxy_type,
871 delay,
872 });
873 Ok(())
874 })
875 }
876
877 pub fn remove_proxy_delegate(
886 delegator: &T::AccountId,
887 delegatee: T::AccountId,
888 proxy_type: T::ProxyType,
889 delay: BlockNumberFor<T>,
890 ) -> DispatchResult {
891 Proxies::<T>::try_mutate_exists(delegator, |x| {
892 let (mut proxies, old_deposit) = x.take().ok_or(Error::<T>::NotFound)?;
893 let proxy_def = ProxyDefinition {
894 delegate: delegatee.clone(),
895 proxy_type: proxy_type.clone(),
896 delay,
897 };
898 let i = proxies.binary_search(&proxy_def).ok().ok_or(Error::<T>::NotFound)?;
899 proxies.remove(i);
900 let new_deposit = Self::deposit(proxies.len() as u32);
901 if new_deposit > old_deposit {
902 T::Currency::reserve(delegator, new_deposit - old_deposit)?;
903 } else if new_deposit < old_deposit {
904 T::Currency::unreserve(delegator, old_deposit - new_deposit);
905 }
906 if !proxies.is_empty() {
907 *x = Some((proxies, new_deposit))
908 }
909 Self::deposit_event(Event::<T>::ProxyRemoved {
910 delegator: delegator.clone(),
911 delegatee,
912 proxy_type,
913 delay,
914 });
915 Ok(())
916 })
917 }
918
919 pub fn deposit(num_proxies: u32) -> BalanceOf<T> {
920 if num_proxies == 0 {
921 Zero::zero()
922 } else {
923 T::ProxyDepositBase::get() + T::ProxyDepositFactor::get() * num_proxies.into()
924 }
925 }
926
927 fn rejig_deposit(
928 who: &T::AccountId,
929 old_deposit: BalanceOf<T>,
930 base: BalanceOf<T>,
931 factor: BalanceOf<T>,
932 len: usize,
933 ) -> Result<Option<BalanceOf<T>>, DispatchError> {
934 let new_deposit =
935 if len == 0 { BalanceOf::<T>::zero() } else { base + factor * (len as u32).into() };
936 if new_deposit > old_deposit {
937 T::Currency::reserve(who, new_deposit.saturating_sub(old_deposit))?;
938 } else if new_deposit < old_deposit {
939 let excess = old_deposit.saturating_sub(new_deposit);
940 let remaining_unreserved = T::Currency::unreserve(who, excess);
941 if !remaining_unreserved.is_zero() {
942 defensive!(
943 "Failed to unreserve full amount. (Requested, Actual)",
944 (excess, excess.saturating_sub(remaining_unreserved))
945 );
946 }
947 }
948 Ok(if len == 0 { None } else { Some(new_deposit) })
949 }
950
951 fn edit_announcements<
952 F: FnMut(&Announcement<T::AccountId, CallHashOf<T>, BlockNumberFor<T>>) -> bool,
953 >(
954 delegate: &T::AccountId,
955 f: F,
956 ) -> DispatchResult {
957 Announcements::<T>::try_mutate_exists(delegate, |x| {
958 let (mut pending, old_deposit) = x.take().ok_or(Error::<T>::NotFound)?;
959 let orig_pending_len = pending.len();
960 pending.retain(f);
961 ensure!(orig_pending_len > pending.len(), Error::<T>::NotFound);
962 *x = Self::rejig_deposit(
963 delegate,
964 old_deposit,
965 T::AnnouncementDepositBase::get(),
966 T::AnnouncementDepositFactor::get(),
967 pending.len(),
968 )?
969 .map(|deposit| (pending, deposit));
970 Ok(())
971 })
972 }
973
974 pub fn find_proxy(
975 real: &T::AccountId,
976 delegate: &T::AccountId,
977 force_proxy_type: Option<T::ProxyType>,
978 ) -> Result<ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>, DispatchError> {
979 let f = |x: &ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>| -> bool {
980 &x.delegate == delegate &&
981 force_proxy_type.as_ref().map_or(true, |y| &x.proxy_type == y)
982 };
983 Ok(Proxies::<T>::get(real).0.into_iter().find(f).ok_or(Error::<T>::NotProxy)?)
984 }
985
986 fn proxy_weight(call_weight: Weight) -> Weight {
988 T::WeightInfo::proxy(T::MaxProxies::get())
989 .saturating_add(T::DbWeight::get().reads_writes(1, 1))
991 .saturating_add(call_weight)
992 }
993
994 fn proxy_announced_weight(call_weight: Weight) -> Weight {
996 T::WeightInfo::proxy_announced(T::MaxPending::get(), T::MaxProxies::get())
997 .saturating_add(T::DbWeight::get().reads_writes(1, 1))
999 .saturating_add(call_weight)
1000 }
1001
1002 fn do_proxy(
1003 def: ProxyDefinition<T::AccountId, T::ProxyType, BlockNumberFor<T>>,
1004 real: T::AccountId,
1005 call: <T as Config>::RuntimeCall,
1006 ) -> DispatchResultWithPostInfo {
1007 use frame::traits::{InstanceFilter as _, OriginTrait as _};
1008 let mut origin: T::RuntimeOrigin = frame_system::RawOrigin::Signed(real).into();
1010 origin.add_filter(move |c: &<T as frame_system::Config>::RuntimeCall| {
1011 let c = <T as Config>::RuntimeCall::from_ref(c);
1012 match c.is_sub_type() {
1014 Some(Call::add_proxy { ref proxy_type, .. }) |
1017 Some(Call::remove_proxy { ref proxy_type, .. })
1018 if !def.proxy_type.is_superset(proxy_type) =>
1019 {
1020 false
1021 },
1022 Some(Call::remove_proxies { .. }) | Some(Call::kill_pure { .. })
1025 if def.proxy_type != T::ProxyType::default() =>
1026 {
1027 false
1028 },
1029 _ => def.proxy_type.filter(c),
1030 }
1031 });
1032 let result = call.dispatch(origin);
1033 Self::deposit_event(Event::ProxyExecuted {
1034 result: result.map(|_| ()).map_err(|e| e.error),
1035 });
1036
1037 result
1038 }
1039
1040 pub fn remove_all_proxy_delegates(delegator: &T::AccountId) {
1045 let (proxies, old_deposit) = Proxies::<T>::take(delegator);
1046 T::Currency::unreserve(delegator, old_deposit);
1047 proxies.into_iter().for_each(|proxy_def| {
1048 Self::deposit_event(Event::<T>::ProxyRemoved {
1049 delegator: delegator.clone(),
1050 delegatee: proxy_def.delegate,
1051 proxy_type: proxy_def.proxy_type,
1052 delay: proxy_def.delay,
1053 });
1054 });
1055 }
1056}
1057
1058fn get_result_weight(result: DispatchResultWithPostInfo) -> Option<Weight> {
1062 match result {
1063 Ok(post_info) => post_info.actual_weight,
1064 Err(err) => err.post_info.actual_weight,
1065 }
1066}