/home/runner/work/torus-substrate/torus-substrate/pallets/permission0/src/lib.rs
Line | Count | Source |
1 | | #![cfg_attr(not(feature = "std"), no_std)] |
2 | | #![allow(clippy::too_many_arguments)] |
3 | | |
4 | | pub mod benchmarking; |
5 | | pub mod weights; |
6 | | pub use weights::*; |
7 | | |
8 | | pub mod ext; |
9 | | pub mod migrations; |
10 | | pub mod permission; |
11 | | |
12 | | pub use pallet::*; |
13 | | |
14 | | pub use permission::{ |
15 | | CuratorPermissions, CuratorScope, DistributionControl, EnforcementAuthority, |
16 | | EnforcementReferendum, PermissionContract, PermissionDuration, PermissionId, PermissionScope, |
17 | | RevocationTerms, StreamAllocation, StreamScope, generate_permission_id, |
18 | | }; |
19 | | |
20 | | pub use pallet_permission0_api::{StreamId, generate_root_stream_id}; |
21 | | |
22 | | use polkadot_sdk::{ |
23 | | frame_support::{ |
24 | | dispatch::DispatchResult, |
25 | | pallet_prelude::*, |
26 | | traits::{Currency, Get, ReservableCurrency}, |
27 | | }, |
28 | | frame_system::{self, pallet_prelude::*}, |
29 | | polkadot_sdk_frame as frame, |
30 | | sp_runtime::{Percent, traits::Saturating}, |
31 | | sp_std::prelude::*, |
32 | | }; |
33 | | |
34 | | #[frame::pallet] |
35 | | pub mod pallet { |
36 | | use pallet_torus0_api::NamespacePathInner; |
37 | | use permission::wallet::WalletStake; |
38 | | use polkadot_sdk::{frame_support::PalletId, sp_core::TryCollect}; |
39 | | |
40 | | use super::*; |
41 | | |
42 | | const STORAGE_VERSION: StorageVersion = StorageVersion::new(7); |
43 | | |
44 | | /// Configure the pallet by specifying the parameters and types on which it depends. |
45 | | #[pallet::config] |
46 | | pub trait Config: polkadot_sdk::frame_system::Config { |
47 | | type RuntimeEvent: From<Event<Self>> |
48 | | + IsType<<Self as polkadot_sdk::frame_system::Config>::RuntimeEvent>; |
49 | | |
50 | | /// Permission0 pallet ID |
51 | | #[pallet::constant] |
52 | | type PalletId: Get<PalletId>; |
53 | | |
54 | | type WeightInfo: WeightInfo; |
55 | | |
56 | | type Currency: ReservableCurrency<Self::AccountId>; |
57 | | |
58 | | type Torus: pallet_torus0_api::Torus0Api<Self::AccountId, BalanceOf<Self>>; |
59 | | |
60 | | /// Maximum number of controllers per permission. |
61 | | #[pallet::constant] |
62 | | type MaxControllersPerPermission: Get<u32>; |
63 | | |
64 | | /// Maximum number of revokers. |
65 | | #[pallet::constant] |
66 | | type MaxRevokersPerPermission: Get<u32>; |
67 | | |
68 | | /// Maximum number of recipients per permission. |
69 | | #[pallet::constant] |
70 | | type MaxRecipientsPerPermission: Get<u32>; |
71 | | |
72 | | /// Maximum number of delegated streams per permission. |
73 | | #[pallet::constant] |
74 | | type MaxStreamsPerPermission: Get<u32>; |
75 | | |
76 | | /// Minimum threshold for auto-distribution |
77 | | #[pallet::constant] |
78 | | type MinAutoDistributionThreshold: Get<BalanceOf<Self>>; |
79 | | |
80 | | /// Maximum number of namespaces a single permission can delegate. |
81 | | #[pallet::constant] |
82 | | type MaxNamespacesPerPermission: Get<u32>; |
83 | | |
84 | | /// Maximum number of curator subpermissions a single permission can delegate. |
85 | | #[pallet::constant] |
86 | | type MaxCuratorSubpermissionsPerPermission: Get<u32>; |
87 | | |
88 | | /// Maximum number of children a single permission can have. |
89 | | #[pallet::constant] |
90 | | type MaxChildrenPerPermission: Get<u32>; |
91 | | |
92 | | /// Max operations a bulk extrinsic can perform per extrinsic call. |
93 | | #[pallet::constant] |
94 | | type MaxBulkOperationsPerCall: Get<u32>; |
95 | | } |
96 | | |
97 | | pub type BalanceOf<T> = |
98 | | <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance; |
99 | | |
100 | | pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId; |
101 | | |
102 | | pub type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency< |
103 | | <T as frame_system::Config>::AccountId, |
104 | | >>::NegativeImbalance; |
105 | | |
106 | | #[pallet::pallet] |
107 | | #[pallet::storage_version(STORAGE_VERSION)] |
108 | | pub struct Pallet<T>(_); |
109 | | |
110 | | /// Active permission contracts - stored by permission ID |
111 | | #[pallet::storage] |
112 | | pub type Permissions<T: Config> = StorageMap<_, Identity, PermissionId, PermissionContract<T>>; |
113 | | |
114 | | /// Mapping from (delegator, recipient) to permission IDs |
115 | | #[pallet::storage] |
116 | | pub type PermissionsByParticipants<T: Config> = StorageMap< |
117 | | _, |
118 | | Identity, |
119 | | (T::AccountId, T::AccountId), |
120 | | BoundedBTreeSet<PermissionId, T::MaxRecipientsPerPermission>, |
121 | | ValueQuery, |
122 | | >; |
123 | | |
124 | | /// Permissions delegated by a specific account |
125 | | #[pallet::storage] |
126 | | pub type PermissionsByDelegator<T: Config> = StorageMap< |
127 | | _, |
128 | | Identity, |
129 | | T::AccountId, |
130 | | BoundedBTreeSet<PermissionId, T::MaxRecipientsPerPermission>, |
131 | | ValueQuery, |
132 | | >; |
133 | | |
134 | | /// Permissions received by a specific account |
135 | | #[pallet::storage] |
136 | | pub type PermissionsByRecipient<T: Config> = StorageMap< |
137 | | _, |
138 | | Identity, |
139 | | T::AccountId, |
140 | | BoundedBTreeSet<PermissionId, T::MaxRecipientsPerPermission>, |
141 | | ValueQuery, |
142 | | >; |
143 | | |
144 | | /// Revocations in progress and the voters |
145 | | #[pallet::storage] |
146 | | pub type RevocationTracking<T: Config> = StorageMap< |
147 | | _, |
148 | | Identity, |
149 | | PermissionId, |
150 | | BoundedBTreeSet<T::AccountId, T::MaxRevokersPerPermission>, |
151 | | ValueQuery, |
152 | | >; |
153 | | |
154 | | /// Enforcement votes in progress and the voters |
155 | | #[pallet::storage] |
156 | | pub type EnforcementTracking<T: Config> = StorageDoubleMap< |
157 | | _, |
158 | | Identity, |
159 | | PermissionId, |
160 | | Identity, |
161 | | EnforcementReferendum, |
162 | | BoundedBTreeSet<T::AccountId, T::MaxControllersPerPermission>, |
163 | | ValueQuery, |
164 | | >; |
165 | | |
166 | | /// Accumulated amounts for each stream |
167 | | #[pallet::storage] |
168 | | pub type AccumulatedStreamAmounts<T: Config> = StorageNMap< |
169 | | _, |
170 | | ( |
171 | | NMapKey<Identity, T::AccountId>, |
172 | | NMapKey<Identity, StreamId>, |
173 | | NMapKey<Identity, PermissionId>, |
174 | | ), |
175 | | BalanceOf<T>, |
176 | | >; |
177 | | |
178 | | #[pallet::event] |
179 | | #[pallet::generate_deposit(pub(super) fn deposit_event)] |
180 | | pub enum Event<T: Config> { |
181 | | /// Permission delegated from delegator to recipient with ID |
182 | | PermissionDelegated { |
183 | | delegator: T::AccountId, |
184 | | permission_id: PermissionId, |
185 | | }, |
186 | | /// Permission revoked with ID |
187 | | PermissionRevoked { |
188 | | delegator: T::AccountId, |
189 | | revoked_by: Option<T::AccountId>, |
190 | | permission_id: PermissionId, |
191 | | }, |
192 | | /// Permission expired with ID |
193 | | PermissionExpired { |
194 | | delegator: T::AccountId, |
195 | | permission_id: PermissionId, |
196 | | }, |
197 | | /// Permission accumulation state toggled |
198 | | PermissionAccumulationToggled { |
199 | | permission_id: PermissionId, |
200 | | accumulating: bool, |
201 | | toggled_by: Option<T::AccountId>, |
202 | | }, |
203 | | /// Permission was executed by enforcement authority |
204 | | PermissionEnforcementExecuted { |
205 | | permission_id: PermissionId, |
206 | | executed_by: Option<T::AccountId>, |
207 | | }, |
208 | | /// Vote for enforcement action |
209 | | EnforcementVoteCast { |
210 | | permission_id: PermissionId, |
211 | | voter: T::AccountId, |
212 | | referendum: EnforcementReferendum, |
213 | | }, |
214 | | /// Enforcement authority set for permission |
215 | | EnforcementAuthoritySet { |
216 | | permission_id: PermissionId, |
217 | | controllers_count: u32, |
218 | | required_votes: u32, |
219 | | }, |
220 | | /// An stream distribution happened |
221 | | StreamDistribution { |
222 | | permission_id: PermissionId, |
223 | | stream_id: Option<StreamId>, |
224 | | recipient: T::AccountId, |
225 | | amount: BalanceOf<T>, |
226 | | reason: permission::stream::DistributionReason, |
227 | | }, |
228 | | /// Accumulated emission for stream |
229 | | AccumulatedEmission { |
230 | | permission_id: PermissionId, |
231 | | stream_id: StreamId, |
232 | | amount: BalanceOf<T>, |
233 | | }, |
234 | | } |
235 | | |
236 | | #[pallet::error] |
237 | | pub enum Error<T> { |
238 | | /// The agent is not registered |
239 | | NotRegisteredAgent, |
240 | | /// Permissions can only be created through extrinsics |
241 | | PermissionCreationOutsideExtrinsic, |
242 | | /// A permission with the same exact parameters was |
243 | | /// already created in the current block |
244 | | DuplicatePermissionInBlock, |
245 | | /// Permission not found |
246 | | PermissionNotFound, |
247 | | /// Self-permission is not allowed |
248 | | SelfPermissionNotAllowed, |
249 | | /// Invalid percentage (out of range) |
250 | | InvalidPercentage, |
251 | | /// Invalid stream weight set to recipient |
252 | | InvalidRecipientWeight, |
253 | | /// No recipients specified |
254 | | NoRecipientsSpecified, |
255 | | /// Invalid threshold |
256 | | InvalidThreshold, |
257 | | /// No accumulated amount |
258 | | NoAccumulatedAmount, |
259 | | /// Not authorized to revoke |
260 | | NotAuthorizedToRevoke, |
261 | | /// Total allocation exceeded 100% |
262 | | TotalAllocationExceeded, |
263 | | /// Not the recipient of the permission |
264 | | NotPermissionRecipient, |
265 | | /// Not the delegator of the permission |
266 | | NotPermissionDelegator, |
267 | | /// Too many streams |
268 | | TooManyStreams, |
269 | | /// Too many recipients |
270 | | TooManyRecipients, |
271 | | /// Too many revokers |
272 | | TooManyRevokers, |
273 | | /// Failed to insert into storage |
274 | | StorageError, |
275 | | /// Invalid amount |
276 | | InvalidAmount, |
277 | | /// Insufficient balance for operation |
278 | | InsufficientBalance, |
279 | | /// Invalid distribution interval |
280 | | InvalidInterval, |
281 | | /// Parent permission not found |
282 | | ParentPermissionNotFound, |
283 | | /// Invalid distribution method |
284 | | InvalidDistributionMethod, |
285 | | /// Revokers and required voters must be at least one, and required voters must |
286 | | /// be less than the number of revokers |
287 | | InvalidNumberOfRevokers, |
288 | | /// Fixed amount streams can only be triggered once, manually or at a block |
289 | | FixedAmountCanOnlyBeTriggeredOnce, |
290 | | /// Unsupported permission type |
291 | | UnsupportedPermissionType, |
292 | | /// Not authorized to toggle permission state |
293 | | NotAuthorizedToToggle, |
294 | | /// Too many controllers |
295 | | TooManyControllers, |
296 | | /// Invalid number of controllers or required votes |
297 | | InvalidNumberOfControllers, |
298 | | /// Permission is a duplicate, revoke the previous one |
299 | | DuplicatePermission, |
300 | | /// Permission is in cooldown, wait a bit. |
301 | | PermissionInCooldown, |
302 | | /// Curator flags provided are invalid. |
303 | | InvalidCuratorPermissions, |
304 | | /// Tried delegating unknown namespace. |
305 | | NamespaceDoesNotExist, |
306 | | /// Namespace path provided contains illegal character or is malformatted. |
307 | | NamespacePathIsInvalid, |
308 | | /// Exceeded amount of total namespaces allowed in a single permission. |
309 | | TooManyNamespaces, |
310 | | /// Not authorized to edit a permission. |
311 | | NotAuthorizedToEdit, |
312 | | /// Permission is not editable |
313 | | NotEditable, |
314 | | /// Namespace creation was disabled by a curator. |
315 | | NamespaceCreationDisabled, |
316 | | /// Deriving a permission from multiple parents is still forbidden. |
317 | | MultiParentForbidden, |
318 | | /// Not enough instances available to delegate/execute a permission. |
319 | | /// This might mean the execution requires more than the available instances |
320 | | /// or that all instances are locked behind redelegations. |
321 | | NotEnoughInstances, |
322 | | /// Too many children for a permission. |
323 | | TooManyChildren, |
324 | | /// Stream managers must have up to two entries and always contain the delegator, |
325 | | InvalidStreamManagers, |
326 | | /// Revocation terms are too strong for a permission re-delegation. |
327 | | RevocationTermsTooStrong, |
328 | | /// Too many curator permissions being delegated in a single permission. |
329 | | TooManyCuratorPermissions, |
330 | | /// Namespace delegation depth exceeded the maximum allowed limit. |
331 | | DelegationDepthExceeded, |
332 | | } |
333 | | |
334 | | #[pallet::hooks] |
335 | | impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> { |
336 | 477k | fn on_finalize(current_block: BlockNumberFor<T>) { |
337 | 477k | permission::do_auto_permission_execution::<T>(current_block); |
338 | 477k | } |
339 | | } |
340 | | |
341 | | #[pallet::call] |
342 | | impl<T: Config> Pallet<T> { |
343 | | /// Delegate a permission for stream delegation |
344 | | #[pallet::call_index(0)] |
345 | | #[pallet::weight(T::WeightInfo::delegate_stream_permission())] |
346 | | pub fn delegate_stream_permission( |
347 | | origin: OriginFor<T>, |
348 | | recipients: BoundedBTreeMap<T::AccountId, u16, T::MaxRecipientsPerPermission>, |
349 | | allocation: StreamAllocation<T>, |
350 | | distribution: DistributionControl<T>, |
351 | | duration: PermissionDuration<T>, |
352 | | revocation: RevocationTerms<T>, |
353 | | enforcement: EnforcementAuthority<T>, |
354 | | recipient_manager: Option<T::AccountId>, |
355 | | weight_setter: Option<T::AccountId>, |
356 | 16 | ) -> DispatchResult { |
357 | 16 | let delegator = ensure_signed(origin)?0 ; |
358 | | |
359 | 16 | ext::stream_impl::delegate_stream_permission_impl::<T>( |
360 | 16 | delegator, |
361 | 16 | recipients, |
362 | 16 | allocation, |
363 | 16 | distribution, |
364 | 16 | duration, |
365 | 16 | revocation, |
366 | 16 | enforcement, |
367 | 16 | recipient_manager, |
368 | 16 | weight_setter, |
369 | 4 | )?; |
370 | | |
371 | 12 | Ok(()) |
372 | | } |
373 | | |
374 | | /// Revoke a permission. The caller must meet revocation constraints or be a root key. |
375 | | #[pallet::call_index(1)] |
376 | | #[pallet::weight(T::WeightInfo::revoke_permission())] |
377 | | pub fn revoke_permission( |
378 | | origin: OriginFor<T>, |
379 | | permission_id: PermissionId, |
380 | 40 | ) -> DispatchResult { |
381 | 40 | ext::revoke_permission_impl::<T>(origin, &permission_id) |
382 | | } |
383 | | |
384 | | /// Execute a manual distribution based on permission |
385 | | #[pallet::call_index(2)] |
386 | | #[pallet::weight(T::WeightInfo::execute_permission())] |
387 | | pub fn execute_permission( |
388 | | origin: OriginFor<T>, |
389 | | permission_id: PermissionId, |
390 | 16 | ) -> DispatchResult { |
391 | 16 | ext::execute_permission_impl::<T>(origin, &permission_id) |
392 | | } |
393 | | |
394 | | /// Toggle a permission's accumulation state (enabled/disabled) |
395 | | /// The caller must be authorized as a controller or be the root key |
396 | | #[pallet::call_index(3)] |
397 | | #[pallet::weight(T::WeightInfo::toggle_permission_accumulation())] |
398 | | pub fn toggle_permission_accumulation( |
399 | | origin: OriginFor<T>, |
400 | | permission_id: PermissionId, |
401 | | accumulating: bool, |
402 | 16 | ) -> DispatchResult { |
403 | 16 | ext::stream_impl::toggle_permission_accumulation_impl::<T>( |
404 | 16 | origin, |
405 | 16 | permission_id, |
406 | 16 | accumulating, |
407 | | ) |
408 | | } |
409 | | |
410 | | /// Execute a permission through enforcement authority |
411 | | /// The caller must be authorized as a controller or be the root key |
412 | | #[pallet::call_index(4)] |
413 | | #[pallet::weight(T::WeightInfo::enforcement_execute_permission())] |
414 | | pub fn enforcement_execute_permission( |
415 | | origin: OriginFor<T>, |
416 | | permission_id: PermissionId, |
417 | 12 | ) -> DispatchResult { |
418 | 12 | ext::enforcement_execute_permission_impl::<T>(origin, permission_id) |
419 | | } |
420 | | |
421 | | /// Set enforcement authority for a permission |
422 | | /// Only the delegator or root can set enforcement authority |
423 | | #[pallet::call_index(5)] |
424 | | #[pallet::weight(T::WeightInfo::set_enforcement_authority())] |
425 | | pub fn set_enforcement_authority( |
426 | | origin: OriginFor<T>, |
427 | | permission_id: PermissionId, |
428 | | enforcement: EnforcementAuthority<T>, |
429 | 6 | ) -> DispatchResult { |
430 | 6 | let who = ensure_signed_or_root(origin)?0 ; |
431 | | |
432 | 6 | let contract = |
433 | 6 | Permissions::<T>::get(permission_id).ok_or(Error::<T>::PermissionNotFound)?0 ; |
434 | | |
435 | 6 | if let Some(who) = &who { |
436 | 6 | ensure!( |
437 | 6 | who == &contract.delegator, |
438 | 4 | Error::<T>::NotPermissionDelegator |
439 | | ); |
440 | 0 | } |
441 | | |
442 | 2 | contract.update_enforcement(permission_id, enforcement) |
443 | | } |
444 | | |
445 | | /// Delegate a permission for curator delegation |
446 | | #[pallet::call_index(6)] |
447 | | #[pallet::weight(T::WeightInfo::delegate_curator_permission())] |
448 | | pub fn delegate_curator_permission( |
449 | | origin: OriginFor<T>, |
450 | | recipient: T::AccountId, |
451 | | flags: BoundedBTreeMap< |
452 | | Option<PermissionId>, |
453 | | u32, |
454 | | T::MaxCuratorSubpermissionsPerPermission, |
455 | | >, |
456 | | cooldown: Option<BlockNumberFor<T>>, |
457 | | duration: PermissionDuration<T>, |
458 | | revocation: RevocationTerms<T>, |
459 | | instances: u32, |
460 | 38 | ) -> DispatchResult { |
461 | 38 | let flags = flags |
462 | 38 | .into_iter() |
463 | 38 | .map(|(pid, flags)| (pid, CuratorPermissions::from_bits_truncate(flags))) |
464 | 38 | .try_collect()?0 ; |
465 | | |
466 | 38 | ext::curator_impl::delegate_curator_permission_impl::<T>( |
467 | 38 | origin, recipient, flags, cooldown, duration, revocation, instances, |
468 | 6 | )?; |
469 | | |
470 | 32 | Ok(()) |
471 | | } |
472 | | |
473 | | /// Delegate a permission over namespaces |
474 | | #[pallet::call_index(7)] |
475 | | #[pallet::weight(T::WeightInfo::delegate_namespace_permission())] |
476 | | pub fn delegate_namespace_permission( |
477 | | origin: OriginFor<T>, |
478 | | recipient: T::AccountId, |
479 | | paths: BoundedBTreeMap< |
480 | | Option<PermissionId>, |
481 | | BoundedBTreeSet<NamespacePathInner, T::MaxNamespacesPerPermission>, |
482 | | T::MaxNamespacesPerPermission, |
483 | | >, |
484 | | duration: PermissionDuration<T>, |
485 | | revocation: RevocationTerms<T>, |
486 | | instances: u32, |
487 | 130 | ) -> DispatchResult { |
488 | 130 | ext::namespace_impl::delegate_namespace_permission_impl::<T>( |
489 | 130 | origin, recipient, paths, duration, revocation, instances, |
490 | 32 | )?; |
491 | | |
492 | 98 | Ok(()) |
493 | | } |
494 | | |
495 | | /// Delegate a permission over namespaces |
496 | | #[pallet::call_index(11)] |
497 | | #[pallet::weight(T::WeightInfo::delegate_namespace_permission())] |
498 | | pub fn delegate_wallet_stake_permission( |
499 | | origin: OriginFor<T>, |
500 | | recipient: T::AccountId, |
501 | | stake_details: WalletStake, |
502 | | duration: PermissionDuration<T>, |
503 | | revocation: RevocationTerms<T>, |
504 | 32 | ) -> DispatchResult { |
505 | 32 | ext::wallet_impl::delegate_wallet_stake_permission::<T>( |
506 | 32 | origin, |
507 | 32 | recipient, |
508 | 32 | stake_details, |
509 | 32 | duration, |
510 | 32 | revocation, |
511 | 6 | )?; |
512 | | |
513 | 26 | Ok(()) |
514 | | } |
515 | | |
516 | | /// Delegate a permission over namespaces to multiple recipients. |
517 | | /// Note: this extrinsic creates _multiple_ permissions with the same |
518 | | /// properties. |
519 | | #[pallet::call_index(10)] |
520 | | #[pallet::weight({ |
521 | | T::WeightInfo::delegate_namespace_permission() |
522 | | .saturating_mul(recipients.len() as u64) |
523 | | })] |
524 | | pub fn bulk_delegate_namespace_permission( |
525 | | origin: OriginFor<T>, |
526 | | recipients: BoundedBTreeSet<T::AccountId, T::MaxBulkOperationsPerCall>, |
527 | | paths: BoundedBTreeMap< |
528 | | Option<PermissionId>, |
529 | | BoundedBTreeSet<NamespacePathInner, T::MaxNamespacesPerPermission>, |
530 | | T::MaxNamespacesPerPermission, |
531 | | >, |
532 | | duration: PermissionDuration<T>, |
533 | | revocation: RevocationTerms<T>, |
534 | | instances: u32, |
535 | 4 | ) -> DispatchResult { |
536 | 10 | for recipient8 in recipients { |
537 | 8 | ext::namespace_impl::delegate_namespace_permission_impl::<T>( |
538 | 8 | origin.clone(), |
539 | 8 | recipient, |
540 | 8 | paths.clone(), |
541 | 8 | duration.clone(), |
542 | 8 | revocation.clone(), |
543 | 8 | instances, |
544 | 2 | )?; |
545 | | } |
546 | | |
547 | 2 | Ok(()) |
548 | | } |
549 | | |
550 | | /// Allows Delegator/Recipient to edit stream permission |
551 | | #[pallet::call_index(8)] |
552 | | #[pallet::weight(T::WeightInfo::delegate_curator_permission())] |
553 | | pub fn update_stream_permission( |
554 | | origin: OriginFor<T>, |
555 | | permission_id: PermissionId, |
556 | | new_recipients: Option< |
557 | | BoundedBTreeMap<T::AccountId, u16, T::MaxRecipientsPerPermission>, |
558 | | >, |
559 | | new_streams: Option<BoundedBTreeMap<StreamId, Percent, T::MaxStreamsPerPermission>>, |
560 | | new_distribution_control: Option<DistributionControl<T>>, |
561 | | new_recipient_manager: Option<Option<T::AccountId>>, |
562 | | new_weight_setter: Option<Option<T::AccountId>>, |
563 | 44 | ) -> DispatchResult { |
564 | 44 | ext::stream_impl::update_stream_permission( |
565 | 44 | origin, |
566 | 44 | permission_id, |
567 | 44 | new_recipients, |
568 | 44 | new_streams, |
569 | 44 | new_distribution_control, |
570 | 44 | new_recipient_manager, |
571 | 44 | new_weight_setter, |
572 | 24 | )?; |
573 | | |
574 | 20 | Ok(()) |
575 | | } |
576 | | |
577 | | /// Allows a delegator to update the number of instances of a permission |
578 | | #[pallet::call_index(9)] |
579 | | #[pallet::weight(T::WeightInfo::update_namespace_permission())] |
580 | | pub fn update_namespace_permission( |
581 | | origin: OriginFor<T>, |
582 | | permission_id: PermissionId, |
583 | | max_instances: u32, |
584 | 22 | ) -> DispatchResult { |
585 | 22 | ext::namespace_impl::update_namespace_permission::<T>( |
586 | 22 | origin, |
587 | 22 | permission_id, |
588 | 22 | max_instances, |
589 | 12 | )?; |
590 | | |
591 | 10 | Ok(()) |
592 | | } |
593 | | |
594 | | #[pallet::call_index(12)] |
595 | | #[pallet::weight(T::WeightInfo::update_namespace_permission())] |
596 | | pub fn execute_wallet_stake_permission( |
597 | | caller: OriginFor<T>, |
598 | | permission_id: PermissionId, |
599 | | op: ext::wallet_impl::WalletStakeOperation<T>, |
600 | 16 | ) -> DispatchResult { |
601 | 16 | ext::wallet_impl::execute_wallet_stake_permission(caller, permission_id, op) |
602 | | } |
603 | | } |
604 | | } |
605 | | |
606 | | /// Get total allocated percentage for a delegator |
607 | 50 | fn get_total_allocated_percentage<T: Config>( |
608 | 50 | delegator: &T::AccountId, |
609 | 50 | stream: &StreamId, |
610 | 50 | ) -> Percent { |
611 | 50 | AccumulatedStreamAmounts::<T>::iter_key_prefix((delegator, stream)) |
612 | 50 | .filter_map(Permissions::<T>::get) |
613 | 50 | .map(|contract| match contract.scope2 { |
614 | | PermissionScope::Stream(StreamScope { |
615 | 2 | allocation: StreamAllocation::Streams(streams), |
616 | | .. |
617 | 2 | }) => streams.get(stream).copied().unwrap_or_default(), |
618 | 0 | _ => Percent::zero(), |
619 | 2 | }) |
620 | 50 | .fold(Percent::zero(), |acc, percentage| {2 |
621 | 2 | acc.saturating_add(percentage) |
622 | 2 | }) |
623 | 50 | } |