Coverage Report

Created: 2025-09-12 14:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/runner/work/torus-substrate/torus-substrate/pallets/permission0/src/ext.rs
Line
Count
Source
1
use crate::permission::EnforcementReferendum;
2
use crate::{
3
    Config, EnforcementAuthority, EnforcementTracking, Error, Event, Pallet, PermissionDuration,
4
    PermissionId, PermissionScope, Permissions, RevocationTerms, pallet,
5
};
6
use pallet_permission0_api::{
7
    EnforcementAuthority as ApiEnforcementAuthority, Permission0Api,
8
    PermissionDuration as ApiPermissionDuration, RevocationTerms as ApiRevocationTerms,
9
};
10
use polkadot_sdk::{
11
    frame_support::ensure,
12
    frame_system::ensure_signed_or_root,
13
    polkadot_sdk_frame::prelude::{BlockNumberFor, OriginFor},
14
    sp_runtime::{DispatchError, DispatchResult},
15
};
16
17
pub mod curator_impl;
18
pub mod namespace_impl;
19
pub mod stream_impl;
20
pub mod wallet_impl;
21
22
/// Implementation of the Permission0Api trait to be used externally
23
impl<T: Config> Permission0Api<OriginFor<T>> for pallet::Pallet<T> {
24
0
    fn permission_exists(id: &PermissionId) -> bool {
25
0
        Permissions::<T>::contains_key(id)
26
0
    }
27
28
0
    fn revoke_permission(who: OriginFor<T>, permission_id: &PermissionId) -> DispatchResult {
29
0
        revoke_permission_impl::<T>(who, permission_id)
30
0
    }
31
32
0
    fn execute_permission(who: OriginFor<T>, permission_id: &PermissionId) -> DispatchResult {
33
0
        execute_permission_impl::<T>(who, permission_id)
34
0
    }
35
}
36
37
68
fn translate_duration<T: Config>(
38
68
    duration: ApiPermissionDuration<BlockNumberFor<T>>,
39
68
) -> Result<PermissionDuration<T>, DispatchError> {
40
68
    Ok(match duration {
41
2
        ApiPermissionDuration::UntilBlock(block) => {
42
2
            let current_block = <polkadot_sdk::frame_system::Pallet<T>>::block_number();
43
2
            ensure!(block > current_block, 
Error::<T>::InvalidInterval0
);
44
45
2
            PermissionDuration::UntilBlock(block)
46
        }
47
66
        ApiPermissionDuration::Indefinite => PermissionDuration::Indefinite,
48
    })
49
68
}
50
51
68
fn translate_revocation_terms<T: Config>(
52
68
    revocation: ApiRevocationTerms<T::AccountId, BlockNumberFor<T>>,
53
68
) -> Result<RevocationTerms<T>, DispatchError> {
54
68
    let 
revocation62
= match revocation {
55
48
        ApiRevocationTerms::Irrevocable => RevocationTerms::Irrevocable,
56
4
        ApiRevocationTerms::RevocableByDelegator => RevocationTerms::RevocableByDelegator,
57
        ApiRevocationTerms::RevocableByArbiters {
58
10
            accounts,
59
10
            required_votes,
60
        } => {
61
10
            ensure!(required_votes > 0, 
Error::<T>::InvalidNumberOfRevokers4
);
62
6
            ensure!(!accounts.is_empty(), 
Error::<T>::InvalidNumberOfRevokers0
);
63
64
6
            ensure!(
65
6
                required_votes as usize <= accounts.len(),
66
2
                Error::<T>::InvalidNumberOfRevokers
67
            );
68
69
            RevocationTerms::RevocableByArbiters {
70
4
                accounts: accounts
71
4
                    .try_into()
72
4
                    .map_err(|_| crate::Error::<T>::TooManyRevokers)
?0
,
73
4
                required_votes,
74
            }
75
        }
76
6
        ApiRevocationTerms::RevocableAfter(block) => {
77
6
            let current_block = <polkadot_sdk::frame_system::Pallet<T>>::block_number();
78
6
            ensure!(block > current_block, 
Error::<T>::InvalidInterval0
);
79
80
6
            RevocationTerms::RevocableAfter(block)
81
        }
82
    };
83
84
62
    Ok(revocation)
85
68
}
86
87
62
fn translate_enforcement_authority<T: Config>(
88
62
    enforcement: ApiEnforcementAuthority<T::AccountId>,
89
62
) -> Result<EnforcementAuthority<T>, DispatchError> {
90
62
    let enforcement = match enforcement {
91
50
        ApiEnforcementAuthority::None => EnforcementAuthority::None,
92
        ApiEnforcementAuthority::ControlledBy {
93
12
            controllers,
94
12
            required_votes,
95
        } => {
96
12
            ensure!(required_votes > 0, 
Error::<T>::InvalidNumberOfControllers0
);
97
12
            ensure!(
98
12
                !controllers.is_empty(),
99
0
                Error::<T>::InvalidNumberOfControllers
100
            );
101
102
12
            ensure!(
103
12
                required_votes as usize <= controllers.len(),
104
0
                Error::<T>::InvalidNumberOfControllers
105
            );
106
107
            EnforcementAuthority::ControlledBy {
108
12
                controllers: controllers
109
12
                    .try_into()
110
12
                    .map_err(|_| crate::Error::<T>::TooManyControllers)
?0
,
111
12
                required_votes,
112
            }
113
        }
114
    };
115
116
62
    Ok(enforcement)
117
62
}
118
119
/// Revoke a permission implementation
120
40
pub(crate) fn revoke_permission_impl<T: Config>(
121
40
    origin: OriginFor<T>,
122
40
    permission_id: &PermissionId,
123
40
) -> DispatchResult {
124
40
    let 
contract38
= Permissions::<T>::get(permission_id).ok_or(Error::<T>::PermissionNotFound)
?2
;
125
38
    contract.revoke(origin, *permission_id)
126
40
}
127
128
/// Execute a permission implementation
129
16
pub(crate) fn execute_permission_impl<T: Config>(
130
16
    who: OriginFor<T>,
131
16
    permission_id: &PermissionId,
132
16
) -> DispatchResult {
133
16
    let who = ensure_signed_or_root(who)
?0
;
134
135
16
    let 
contract14
= Permissions::<T>::get(permission_id).ok_or(Error::<T>::PermissionNotFound)
?2
;
136
137
14
    let delegator = contract.delegator.clone();
138
139
14
    ensure!(
140
14
        who.is_none() || 
who.as_ref() == Some(&delegator)12
,
141
0
        Error::<T>::NotPermissionDelegator
142
    );
143
144
14
    match &contract.scope {
145
12
        PermissionScope::Stream(stream_scope) => {
146
12
            stream_impl::execute_permission_impl(permission_id, &contract, stream_scope)
147
        }
148
2
        PermissionScope::Curator(_) => curator_impl::execute_permission_impl::<T>(permission_id),
149
0
        PermissionScope::Namespace(_) => Ok(()),
150
0
        PermissionScope::Wallet(_) => Ok(()),
151
    }
152
16
}
153
154
/// Execute a permission through enforcement authority
155
12
pub fn enforcement_execute_permission_impl<T: Config>(
156
12
    origin: OriginFor<T>,
157
12
    permission_id: PermissionId,
158
12
) -> DispatchResult {
159
12
    let who = ensure_signed_or_root(origin)
?0
;
160
161
12
    let contract = Permissions::<T>::get(permission_id).ok_or(Error::<T>::PermissionNotFound)
?0
;
162
163
    // If not root, check enforcement authority
164
12
    if let Some(who) = &who {
165
12
        match &contract.enforcement {
166
            EnforcementAuthority::None => {
167
0
                return Err(Error::<T>::NotAuthorizedToToggle.into());
168
            }
169
            EnforcementAuthority::ControlledBy {
170
12
                controllers,
171
12
                required_votes,
172
            } => {
173
12
                ensure!(controllers.contains(who), 
Error::<T>::NotAuthorizedToToggle2
);
174
175
10
                let referendum = EnforcementReferendum::Execution;
176
10
                let votes = EnforcementTracking::<T>::get(permission_id, &referendum)
177
10
                    .into_iter()
178
10
                    .filter(|id| 
id4
!=
who4
)
179
10
                    .filter(|id| 
controllers2
.
contains2
(
id2
))
180
10
                    .count();
181
182
10
                if votes.saturating_add(1) < *required_votes as usize {
183
4
                    return EnforcementTracking::<T>::mutate(
184
4
                        permission_id,
185
4
                        referendum.clone(),
186
4
                        |votes| {
187
4
                            votes
188
4
                                .try_insert(who.clone())
189
4
                                .map_err(|_| Error::<T>::TooManyControllers)
?0
;
190
191
4
                            <Pallet<T>>::deposit_event(Event::EnforcementVoteCast {
192
4
                                permission_id,
193
4
                                voter: who.clone(),
194
4
                                referendum,
195
4
                            });
196
197
4
                            Ok(())
198
4
                        },
199
                    );
200
6
                }
201
            }
202
        }
203
0
    }
204
205
6
    match &contract.scope {
206
6
        PermissionScope::Stream(stream_scope) => {
207
6
            stream_impl::execute_permission_impl(&permission_id, &contract, stream_scope)
?2
208
        }
209
        PermissionScope::Curator(_) => {
210
0
            return curator_impl::execute_permission_impl::<T>(&permission_id);
211
        }
212
0
        PermissionScope::Namespace(_) => return Ok(()),
213
0
        PermissionScope::Wallet(_) => return Ok(()),
214
    }
215
216
4
    EnforcementTracking::<T>::remove(permission_id, EnforcementReferendum::Execution);
217
218
4
    <Pallet<T>>::deposit_event(Event::PermissionEnforcementExecuted {
219
4
        permission_id,
220
4
        executed_by: who,
221
4
    });
222
223
4
    Ok(())
224
12
}