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