1use codec::{Decode, Encode, MaxEncodedLen};
2use pallet_governance_api::GovernanceApi;
3use pallet_permission0_api::Permission0NamespacesApi;
4use polkadot_sdk::{
5 frame_support::{
6 traits::{ExistenceRequirement, ReservableCurrency},
7 CloneNoBound, DebugNoBound, EqNoBound, PartialEqNoBound,
8 },
9 frame_system::{self, pallet_prelude::BlockNumberFor},
10 sp_runtime::{
11 traits::{One, Saturating, Zero},
12 DispatchResult, FixedPointNumber, FixedU128,
13 },
14};
15use scale_info::TypeInfo;
16
17use crate::*;
18
19pub use pallet_torus0_api::{
20 NamespacePath, MAX_NAMESPACE_PATH_LENGTH, MAX_NAMESPACE_SEGMENTS, MAX_SEGMENT_LENGTH,
21 NAMESPACE_SEPARATOR,
22};
23
24#[derive(
26 Encode, Decode, CloneNoBound, DebugNoBound, PartialEqNoBound, EqNoBound, TypeInfo, MaxEncodedLen,
27)]
28#[scale_info(skip_type_params(T))]
29pub enum NamespaceOwnership<T: Config> {
30 System,
32 Account(T::AccountId),
34}
35
36#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen, DebugNoBound)]
37#[scale_info(skip_type_params(T))]
38pub struct NamespacePricingConfig<T: Config> {
39 pub deposit_per_byte: BalanceOf<T>,
41 pub base_fee: BalanceOf<T>,
45
46 pub count_midpoint: u32,
51 pub fee_steepness: Percent,
53 pub max_fee_multiplier: u32,
55}
56
57impl<T: Config> NamespacePricingConfig<T> {
58 pub fn namespace_fee(
60 &self,
61 account_namespace_count: u32,
62 ) -> Result<BalanceOf<T>, polkadot_sdk::sp_runtime::DispatchError> {
63 let Self {
64 base_fee,
65 count_midpoint,
66 fee_steepness,
67 max_fee_multiplier,
68 ..
69 } = self;
70
71 let multiplier = {
72 let fee_steepness = fee_steepness.deconstruct() as f64 / 100.;
73 let position = (account_namespace_count as i64).saturating_sub(*count_midpoint as i64);
74 let adjusted = -fee_steepness * position as f64;
75 let exp = (libm::exp(adjusted) * FixedU128::DIV as f64) as u128;
76
77 let max_fee_multiplier = FixedU128::from_u32(*max_fee_multiplier);
78
79 FixedU128::one().saturating_add(
80 max_fee_multiplier.saturating_mul(
81 FixedU128::one()
82 .const_checked_div(
83 FixedU128::one().saturating_add(FixedU128::from_inner(exp)),
84 )
85 .unwrap_or_default(),
86 ),
87 )
88 };
89
90 let base_fee = FixedU128::from_inner(*base_fee);
91 Ok(base_fee.saturating_mul(multiplier).into_inner())
92 }
93
94 pub fn namespace_deposit(&self, path: &NamespacePath) -> BalanceOf<T> {
98 self.deposit_per_byte
99 .saturating_mul((path.as_bytes().len() as u32).into())
100 }
101
102 pub fn fee_midpoint(&self) -> BalanceOf<T> {
104 self.base_fee.saturating_add(
105 FixedU128::from_u32(self.max_fee_multiplier)
106 .const_checked_div(FixedU128::from_u32(2))
107 .unwrap_or_default()
108 .saturating_mul(FixedU128::from_inner(self.base_fee))
109 .into_inner(),
110 )
111 }
112
113 pub fn fee_ceiling(&self) -> BalanceOf<T> {
115 self.base_fee.saturating_add(
116 FixedU128::from_u32(self.max_fee_multiplier)
117 .saturating_mul(FixedU128::from_inner(self.base_fee))
118 .into_inner(),
119 )
120 }
121}
122
123#[derive(
125 Encode, Decode, CloneNoBound, PartialEqNoBound, EqNoBound, TypeInfo, MaxEncodedLen, DebugNoBound,
126)]
127#[scale_info(skip_type_params(T))]
128pub struct NamespaceMetadata<T: Config> {
129 pub created_at: BlockNumberFor<T>,
131 pub deposit: BalanceOf<T>,
133}
134
135pub fn find_missing_paths<T: Config>(
136 owner: &NamespaceOwnership<T>,
137 path: &NamespacePath,
138) -> Vec<NamespacePath> {
139 let mut paths_to_create = path.parents();
140 paths_to_create.insert(0, path.clone());
141
142 let mut iter = paths_to_create.iter().enumerate().rev();
143 if matches!(owner, NamespaceOwnership::Account(_))
144 && path.root().as_ref().map(NamespacePath::as_bytes) == Some(&b"agent"[..])
145 {
146 let _ = iter.by_ref().next();
148 }
149
150 for (i, segment) in iter {
151 if !Namespaces::<T>::contains_key(owner, segment) {
152 return paths_to_create.get(..=i).unwrap_or_default().to_vec();
153 }
154 }
155
156 Default::default()
157}
158
159pub fn calculate_cost<T: Config>(
161 owner: &NamespaceOwnership<T>,
162 missing_paths: &[NamespacePath],
163) -> Result<(BalanceOf<T>, BalanceOf<T>), DispatchError> {
164 let current_count = NamespaceCount::<T>::get(owner);
165
166 let pricing_config = crate::NamespacePricingConfig::<T>::get();
167 let mut total_fee = BalanceOf::<T>::zero();
168 let mut total_deposit = BalanceOf::<T>::zero();
169
170 for (index, path) in missing_paths.iter().enumerate() {
171 let count = current_count.saturating_add(index as u32);
172 let fee = pricing_config.namespace_fee(count)?;
173 let deposit = pricing_config.namespace_deposit(path);
174
175 total_fee = total_fee.saturating_add(fee);
176 total_deposit = total_deposit.saturating_add(deposit);
177 }
178
179 Ok((total_fee, total_deposit))
180}
181
182pub fn create_namespace<T: Config>(
183 owner: NamespaceOwnership<T>,
184 path: NamespacePath,
185) -> DispatchResult {
186 #[allow(deprecated)]
187 create_namespace0(owner, path, true)
188}
189
190#[doc(hidden)]
191#[deprecated = "use crate_namespace instead"]
192pub(crate) fn create_namespace0<T: Config>(
193 owner: NamespaceOwnership<T>,
194 path: NamespacePath,
195 charge: bool,
196) -> DispatchResult {
197 ensure!(
198 !Namespaces::<T>::contains_key(&owner, &path),
199 Error::<T>::NamespaceAlreadyExists
200 );
201
202 if let NamespaceOwnership::Account(owner) = &owner {
203 let path_agent = path
204 .segments()
205 .nth(1)
206 .ok_or(Error::<T>::InvalidNamespacePath)?;
207 let agent = Agents::<T>::get(owner).ok_or(Error::<T>::AgentDoesNotExist)?;
208
209 ensure!(path_agent == *agent.name, Error::<T>::InvalidNamespacePath);
210 }
211
212 let missing_paths = find_missing_paths::<T>(&owner, &path);
213
214 if charge {
215 let (total_fee, total_deposit) = calculate_cost::<T>(&owner, &missing_paths)?;
216
217 if let NamespaceOwnership::Account(owner) = &owner {
218 T::Currency::reserve(owner, total_deposit)?;
219
220 <T as crate::Config>::Currency::transfer(
221 owner,
222 &<T as crate::Config>::Governance::dao_treasury_address(),
223 total_fee,
224 ExistenceRequirement::AllowDeath,
225 )
226 .map_err(|_| crate::Error::<T>::NotEnoughBalanceToRegisterAgent)?;
227 }
228 }
229
230 let current_block = <frame_system::Pallet<T>>::block_number();
231 let pricing_config = crate::NamespacePricingConfig::<T>::get();
232
233 for path in missing_paths.iter() {
234 let deposit = if charge {
235 pricing_config.namespace_deposit(path)
236 } else {
237 Zero::zero()
238 };
239
240 let metadata = NamespaceMetadata {
241 created_at: current_block,
242 deposit,
243 };
244
245 Namespaces::<T>::insert(&owner, path, metadata);
246 }
247
248 NamespaceCount::<T>::mutate(&owner, |count| {
249 *count = count.saturating_add(missing_paths.len() as u32)
250 });
251
252 Pallet::<T>::deposit_event(Event::NamespaceCreated { owner, path });
253
254 Ok(())
255}
256
257pub fn delete_namespace<T: Config>(
258 owner: NamespaceOwnership<T>,
259 path: NamespacePath,
260) -> DispatchResult {
261 ensure!(
262 Namespaces::<T>::contains_key(&owner, &path),
263 Error::<T>::NamespaceNotFound
264 );
265
266 if let NamespaceOwnership::Account(owner) = &owner {
267 ensure!(
268 !T::Permission0::is_delegating_namespace(owner, &path),
269 Error::<T>::NamespaceBeingDelegated
270 );
271 }
272
273 let mut total_deposit = BalanceOf::<T>::zero();
274 let namespaces_to_delete: Vec<_> = Namespaces::<T>::iter_prefix(&owner)
275 .filter_map(|(other, metadata)| {
276 if other == path || path.is_parent_of(&other) {
277 Some((other, metadata.deposit))
278 } else {
279 None
280 }
281 })
282 .collect();
283
284 let deleted_count = namespaces_to_delete.len() as u32;
285
286 for (path_to_delete, deposit) in namespaces_to_delete {
287 total_deposit = total_deposit.saturating_add(deposit);
288 Namespaces::<T>::remove(&owner, &path_to_delete);
289 }
290
291 NamespaceCount::<T>::mutate(&owner, |count| *count = count.saturating_sub(deleted_count));
292
293 if let NamespaceOwnership::Account(owner) = &owner {
294 T::Currency::unreserve(owner, total_deposit);
295 }
296
297 Pallet::<T>::deposit_event(Event::NamespaceDeleted { owner, path });
298
299 Ok(())
300}