1pub mod v5 {
2 use num_traits::Zero;
3 use polkadot_sdk::{
4 frame_support::{migrations::VersionedMigration, traits::UncheckedOnRuntimeUpgrade},
5 sp_runtime::BoundedBTreeMap,
6 sp_tracing::warn,
7 sp_weights::Weight,
8 };
9
10 use crate::{
11 Config, EmissionAllocation, Pallet, PermissionId, PermissionScope,
12 permission::CuratorScope, permission::NamespaceScope,
13 };
14
15 pub type Migration<T, W> = VersionedMigration<3, 5, MigrateToV4<T>, Pallet<T>, W>;
16 pub struct MigrateToV4<T>(core::marker::PhantomData<T>);
17
18 mod old_storage {
19 use codec::{Decode, Encode, MaxEncodedLen};
20 use pallet_torus0_api::NamespacePath;
21 use polkadot_sdk::{
22 frame_support::Identity,
23 frame_support_procedural::storage_alias,
24 polkadot_sdk_frame::prelude::BlockNumberFor,
25 sp_runtime::{BoundedBTreeSet, BoundedVec},
26 };
27 use scale_info::TypeInfo;
28
29 use crate::{
30 AccountIdOf, Config, CuratorPermissions, EmissionScope, Pallet, PermissionId,
31 permission::{EnforcementAuthority, PermissionDuration},
32 };
33
34 #[storage_alias]
35 pub type Permissions<T: Config> =
36 StorageMap<Pallet<T>, Identity, PermissionId, PermissionContract<T>>;
37
38 #[storage_alias]
39 pub type PermissionsByGrantor<T: Config> = StorageMap<
40 Pallet<T>,
41 Identity,
42 AccountIdOf<T>,
43 BoundedVec<PermissionId, <T as Config>::MaxTargetsPerPermission>,
44 >;
45
46 #[storage_alias]
47 pub type PermissionsByGrantee<T: Config> = StorageMap<
48 Pallet<T>,
49 Identity,
50 AccountIdOf<T>,
51 BoundedVec<PermissionId, <T as Config>::MaxTargetsPerPermission>,
52 >;
53
54 #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
55 #[scale_info(skip_type_params(T))]
56 pub struct PermissionContract<T: crate::Config> {
57 pub grantor: T::AccountId,
58 pub grantee: T::AccountId,
59 pub scope: PermissionScope<T>,
60 pub duration: PermissionDuration<T>,
61 pub revocation: RevocationTerms<T>,
62 pub enforcement: EnforcementAuthority<T>,
64 pub last_execution: Option<BlockNumberFor<T>>,
66 pub execution_count: u32,
68 pub parent: Option<PermissionId>,
70 pub created_at: BlockNumberFor<T>,
71 }
72
73 #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
75 #[scale_info(skip_type_params(T))]
76 pub enum PermissionScope<T: Config> {
77 Emission(EmissionScope<T>),
78 Curator(CuratorScope<T>),
79 Namespace(NamespaceScope<T>),
80 }
81
82 #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
84 #[scale_info(skip_type_params(T))]
85 pub struct NamespaceScope<T: Config> {
86 pub paths: BoundedBTreeSet<NamespacePath, T::MaxNamespacesPerPermission>,
88 }
89
90 #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
91 #[scale_info(skip_type_params(T))]
92 pub struct CuratorScope<T: Config> {
93 pub flags: CuratorPermissions,
94 pub cooldown: Option<BlockNumberFor<T>>,
95 }
96
97 #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
98 #[scale_info(skip_type_params(T))]
99 pub enum RevocationTerms<T: Config> {
100 Irrevocable,
102 RevocableByGrantor,
104 RevocableByArbiters {
106 accounts: BoundedVec<T::AccountId, T::MaxRevokersPerPermission>,
107 required_votes: u32,
108 },
109 RevocableAfter(BlockNumberFor<T>),
111 }
112 }
113
114 impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV4<T> {
115 fn on_runtime_upgrade() -> Weight {
116 let _ = old_storage::PermissionsByGrantor::<T>::clear(u32::MAX, None);
117 let _ = old_storage::PermissionsByGrantee::<T>::clear(u32::MAX, None);
118
119 for (pid, contract) in old_storage::Permissions::<T>::iter() {
120 if let old_storage::PermissionScope::Emission(scope) = &contract.scope {
121 if let EmissionAllocation::Streams(streams) = &scope.allocation {
122 for stream in streams.keys() {
123 if !crate::AccumulatedStreamAmounts::<T>::contains_key((
124 &contract.grantor,
125 &stream,
126 &pid,
127 )) {
128 warn!(
129 "inserting accumulated stream value for broken contract: {pid}, stream: {stream}"
130 );
131 crate::AccumulatedStreamAmounts::<T>::set(
132 (&contract.grantor, &stream, &pid),
133 Some(Zero::zero()),
134 );
135 }
136 }
137 }
138 }
139
140 crate::PermissionsByDelegator::<T>::mutate(&contract.grantor, |pids| {
141 let _ = pids.try_push(pid);
142 });
143
144 crate::PermissionsByRecipient::<T>::mutate(&contract.grantee, |pids| {
145 let _ = pids.try_push(pid);
146 });
147
148 let scope = match contract.scope {
149 old_storage::PermissionScope::Emission(scope) => {
150 PermissionScope::Emission(scope)
151 }
152 old_storage::PermissionScope::Curator(scope) => PermissionScope::Curator({
153 let mut flags = BoundedBTreeMap::new();
154 let _ = flags.try_insert(Option::<PermissionId>::None, scope.flags);
155 CuratorScope {
156 flags,
157 cooldown: scope.cooldown,
158 }
159 }),
160 old_storage::PermissionScope::Namespace(scope) => PermissionScope::Namespace({
161 let mut paths = BoundedBTreeMap::new();
162 let _ = paths.try_insert(Option::<PermissionId>::None, scope.paths);
163 NamespaceScope { paths }
164 }),
165 };
166
167 let revocation = match contract.revocation {
168 old_storage::RevocationTerms::Irrevocable => {
169 crate::RevocationTerms::Irrevocable
170 }
171 old_storage::RevocationTerms::RevocableByGrantor => {
172 crate::RevocationTerms::RevocableByDelegator
173 }
174 old_storage::RevocationTerms::RevocableByArbiters {
175 accounts,
176 required_votes,
177 } => crate::RevocationTerms::RevocableByArbiters {
178 accounts,
179 required_votes,
180 },
181 old_storage::RevocationTerms::RevocableAfter(block) => {
182 crate::RevocationTerms::RevocableAfter(block)
183 }
184 };
185
186 let mut new = crate::PermissionContract::<T>::new(
187 contract.grantor,
188 contract.grantee,
189 scope,
190 contract.duration,
191 revocation,
192 contract.enforcement,
193 1,
194 );
195
196 new.created_at = contract.created_at;
197 #[allow(deprecated)]
198 new.set_execution_info(contract.last_execution, contract.execution_count);
199
200 crate::Permissions::<T>::set(pid, Some(new));
201 }
202
203 Weight::zero()
204 }
205 }
206}