pallet_permission0/ext/
namespace_impl.rs

1use crate::{
2    generate_permission_id, permission::NamespaceScope, update_permission_indices, Config, Error,
3    Event, Pallet, PermissionContract, PermissionDuration, PermissionId, PermissionScope,
4    Permissions, PermissionsByGrantor, RevocationTerms,
5};
6use pallet_permission0_api::Permission0NamespacesApi;
7use pallet_torus0_api::{NamespacePath, NamespacePathInner, Torus0Api};
8use polkadot_sdk::{
9    frame_support::ensure,
10    frame_system::{self, ensure_signed},
11    polkadot_sdk_frame::prelude::OriginFor,
12    sp_runtime::{BoundedBTreeSet, DispatchError},
13    sp_std::collections::btree_set::BTreeSet,
14};
15
16impl<T: Config> Permission0NamespacesApi<T::AccountId, NamespacePath> for Pallet<T> {
17    fn is_delegating_namespace(grantor: &T::AccountId, path: &NamespacePath) -> bool {
18        PermissionsByGrantor::<T>::get(grantor).iter().any(|id| {
19            Permissions::<T>::get(id)
20                .filter(|permission| {
21                    if let PermissionScope::Namespace(scope) = &permission.scope {
22                        for p in &scope.paths {
23                            if p == path || path.is_parent_of(p) {
24                                return true;
25                            }
26                        }
27                    }
28
29                    false
30                })
31                .is_some()
32        })
33    }
34}
35
36pub fn grant_namespace_permission_impl<T: Config>(
37    grantor: OriginFor<T>,
38    grantee: T::AccountId,
39    paths: BoundedBTreeSet<NamespacePathInner, T::MaxNamespacesPerPermission>,
40    duration: PermissionDuration<T>,
41    revocation: RevocationTerms<T>,
42) -> Result<PermissionId, DispatchError> {
43    let grantor = ensure_signed(grantor)?;
44
45    let paths = paths
46        .into_iter()
47        .map(|path| {
48            let path =
49                NamespacePath::new_agent(&path).map_err(|_| Error::<T>::NamespacePathIsInvalid)?;
50            ensure!(
51                T::Torus::namespace_exists(&grantor, &path),
52                Error::<T>::NamespaceDoesNotExist
53            );
54
55            Ok(path)
56        })
57        .collect::<Result<BTreeSet<NamespacePath>, DispatchError>>()?;
58    let paths = paths
59        .try_into()
60        .map_err(|_| Error::<T>::NamespacePathIsInvalid)?;
61
62    let scope = PermissionScope::Namespace(NamespaceScope { paths });
63    let permission_id = generate_permission_id::<T>(&grantor, &grantee, &scope)?;
64
65    let contract = PermissionContract {
66        grantor,
67        grantee,
68        scope,
69        duration,
70        revocation,
71        enforcement: crate::EnforcementAuthority::None,
72        last_execution: None,
73        execution_count: 0,
74        // Will change once we have a ROOT curator.
75        parent: None,
76        created_at: <frame_system::Pallet<T>>::block_number(),
77    };
78
79    Permissions::<T>::insert(permission_id, &contract);
80    update_permission_indices::<T>(&contract.grantor, &contract.grantee, permission_id)?;
81
82    <Pallet<T>>::deposit_event(Event::PermissionGranted {
83        grantor: contract.grantor,
84        grantee: contract.grantee,
85        permission_id,
86    });
87
88    Ok(permission_id)
89}