pallet_torus0/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3pub mod agent;
4pub mod burn;
5mod ext;
6pub mod fee;
7pub mod migrations;
8pub mod namespace;
9pub mod stake;
10
11pub mod benchmarking;
12pub mod weights;
13
14pub(crate) use ext::*;
15use frame::{
16    arithmetic::Percent,
17    prelude::{ensure_root, ensure_signed},
18};
19use namespace::{NamespaceMetadata, NamespaceOwnership, NamespacePath};
20pub use pallet::*;
21use polkadot_sdk::{
22    frame_support::{
23        Identity,
24        dispatch::DispatchResult,
25        pallet_prelude::{ValueQuery, *},
26        traits::Currency,
27    },
28    frame_system::pallet_prelude::OriginFor,
29    polkadot_sdk_frame as frame, sp_std,
30};
31use scale_info::prelude::vec::Vec;
32
33use crate::{agent::Agent, burn::BurnConfiguration, fee::ValidatorFeeConstraints};
34
35#[frame::pallet]
36pub mod pallet {
37    const STORAGE_VERSION: StorageVersion = StorageVersion::new(6);
38
39    use frame::prelude::BlockNumberFor;
40    use pallet_emission0_api::Emission0Api;
41    use pallet_governance_api::GovernanceApi;
42    use pallet_permission0_api::{Permission0NamespacesApi, Permission0WalletApi, WalletScopeType};
43    use pallet_torus0_api::NamespacePathInner;
44    use polkadot_sdk::frame_support::traits::{NamedReservableCurrency, ReservableCurrency};
45    use weights::WeightInfo;
46
47    use super::*;
48
49    /// Max allowed of validators. This is used then calculating emissions, only
50    /// the top staked agents up to this value will have their weights
51    /// considered.
52    #[pallet::storage]
53    pub type MaxAllowedValidators<T: Config> =
54        StorageValue<_, u16, ValueQuery, T::DefaultMaxAllowedValidators>;
55
56    /// Amount of tokens to burn from a payer key when registering new agents.
57    #[pallet::storage]
58    pub type Burn<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
59
60    /// Number of agent registrations that happened in the last
61    /// [`BurnConfiguration::target_registrations_interval`] blocks.
62    #[pallet::storage]
63    pub type RegistrationsThisInterval<T: Config> = StorageValue<_, u16, ValueQuery>;
64
65    /// Minimum required stake for an agent to be considered a validator.
66    #[pallet::storage]
67    pub type MinValidatorStake<T: Config> =
68        StorageValue<_, BalanceOf<T>, ValueQuery, T::DefaultMinValidatorStake>;
69
70    /// Number of blocks between emissions.
71    #[pallet::storage]
72    pub type RewardInterval<T: Config> = StorageValue<_, u16, ValueQuery, T::DefaultRewardInterval>;
73
74    /// Known registered network agents indexed by the owner's key.
75    #[pallet::storage]
76    pub type Agents<T: Config> = StorageMap<_, Identity, AccountIdOf<T>, Agent<T>>;
77
78    /// Maximum number of characters allowed in an agent name.
79    #[pallet::storage]
80    pub type MaxNameLength<T: Config> = StorageValue<_, u16, ValueQuery, T::DefaultMaxNameLength>;
81
82    /// Minimum number of characters required in an agent name.
83    #[pallet::storage]
84    pub type MinNameLength<T: Config> = StorageValue<_, u16, ValueQuery, T::DefaultMinNameLength>;
85
86    /// Maximum number of characters allowed in an agent URL.
87    #[pallet::storage]
88    pub type MaxAgentUrlLength<T: Config> =
89        StorageValue<_, u16, ValueQuery, T::DefaultMaxAgentUrlLength>;
90
91    /// Number of agent registrations that happened this block.
92    #[pallet::storage]
93    pub type RegistrationsThisBlock<T> = StorageValue<_, u16, ValueQuery>;
94
95    /// Maximum amount of agent registrations per block, tracked by
96    /// [`RegistrationsThisBlock`].
97    #[pallet::storage]
98    pub type MaxRegistrationsPerBlock<T: Config> =
99        StorageValue<_, u16, ValueQuery, T::DefaultMaxRegistrationsPerBlock>;
100
101    // Map of staked tokens prefixed by the staker, and indexed by the staked agents
102    // mapping to the amount in tokens.
103    #[pallet::storage]
104    pub type StakingTo<T: Config> =
105        StorageDoubleMap<_, Identity, T::AccountId, Identity, T::AccountId, BalanceOf<T>>;
106
107    // Map of staked tokens prefixed by the staked agent, and indexed by the staker
108    // keys mapping to the amount in tokens.
109    #[pallet::storage]
110    pub type StakedBy<T: Config> =
111        StorageDoubleMap<_, Identity, T::AccountId, Identity, T::AccountId, BalanceOf<T>>;
112
113    /// The total amount of stake in the network.
114    #[pallet::storage]
115    pub type TotalStake<T> = StorageValue<_, BalanceOf<T>, ValueQuery>;
116
117    /// Minimum amount of stake in tokens a key has to deposit in an agent.
118    #[pallet::storage]
119    pub type MinAllowedStake<T: Config> =
120        StorageValue<_, BalanceOf<T>, ValueQuery, T::DefaultMinAllowedStake>;
121
122    /// The weight dividends have when finding agents to prune. 100% meaning it
123    /// is taking fully into account.
124    #[pallet::storage]
125    pub type DividendsParticipationWeight<T: Config> =
126        StorageValue<_, Percent, ValueQuery, T::DefaultDividendsParticipationWeight>;
127
128    /// Constraints defining validation of agent fees.
129    #[pallet::storage]
130    pub type FeeConstraints<T: Config> = StorageValue<_, ValidatorFeeConstraints<T>, ValueQuery>;
131
132    /// [`Burn`] configuration values.
133    #[pallet::storage]
134    pub type BurnConfig<T: Config> = StorageValue<_, BurnConfiguration<T>, ValueQuery>;
135
136    /// Cooldown (in blocks) in which an agent needs to wait between each `update_agent` call.
137    #[pallet::storage]
138    pub type AgentUpdateCooldown<T: Config> =
139        StorageValue<_, BlockNumberFor<T>, ValueQuery, T::DefaultAgentUpdateCooldown>;
140
141    /// Namespace registry - maps (owner, path) to metadata
142    #[pallet::storage]
143    pub type Namespaces<T: Config> = StorageDoubleMap<
144        _,
145        Blake2_128Concat,
146        NamespaceOwnership<T>,
147        Blake2_128Concat,
148        NamespacePath,
149        NamespaceMetadata<T>,
150    >;
151
152    /// Count of namespaces registered per account
153    #[pallet::storage]
154    pub type NamespaceCount<T: Config> =
155        StorageMap<_, Blake2_128Concat, NamespaceOwnership<T>, u32, ValueQuery>;
156
157    #[pallet::storage]
158    pub type NamespacePricingConfig<T: Config> = StorageValue<
159        _,
160        namespace::NamespacePricingConfig<T>,
161        ValueQuery,
162        T::DefaultNamespacePricingConfig,
163    >;
164
165    #[pallet::hooks]
166    impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
167        fn on_initialize(block_number: BlockNumberFor<T>) -> Weight {
168            let current_block: u64 = block_number
169                .try_into()
170                .ok()
171                .expect("blockchain won't pass 2 ^ 64 blocks");
172
173            burn::adjust_burn::<T>(current_block);
174
175            RegistrationsThisBlock::<T>::set(0);
176
177            Weight::default()
178        }
179    }
180
181    #[pallet::config]
182    pub trait Config: polkadot_sdk::frame_system::Config {
183        #[pallet::constant]
184        type DefaultMaxAllowedValidators: Get<u16>;
185
186        #[pallet::constant]
187        type DefaultMinValidatorStake: Get<BalanceOf<Self>>;
188
189        #[pallet::constant]
190        type DefaultRewardInterval: Get<u16>;
191
192        #[pallet::constant]
193        type DefaultMinNameLength: Get<u16>;
194
195        #[pallet::constant]
196        type DefaultMaxNameLength: Get<u16>;
197
198        #[pallet::constant]
199        type DefaultMaxAgentUrlLength: Get<u16>;
200
201        #[pallet::constant]
202        type DefaultMaxRegistrationsPerBlock: Get<u16>;
203
204        #[pallet::constant]
205        type DefaultMinAllowedStake: Get<BalanceOf<Self>>;
206
207        #[pallet::constant]
208        type DefaultMinStakingFee: Get<u8>;
209
210        #[pallet::constant]
211        type DefaultMinWeightControlFee: Get<u8>;
212
213        #[pallet::constant]
214        type DefaultMinBurn: Get<BalanceOf<Self>>;
215
216        #[pallet::constant]
217        type DefaultMaxBurn: Get<BalanceOf<Self>>;
218
219        #[pallet::constant]
220        type DefaultAdjustmentAlpha: Get<u64>;
221
222        #[pallet::constant]
223        type DefaultTargetRegistrationsInterval: Get<BlockNumberFor<Self>>;
224
225        #[pallet::constant]
226        type DefaultTargetRegistrationsPerInterval: Get<u16>;
227
228        #[pallet::constant]
229        type DefaultMaxRegistrationsPerInterval: Get<u16>;
230
231        /// The storage MaxNameLength should be constrained to be no more than
232        /// the value of this. This is needed on agent::Agent to set the
233        /// `name` field BoundedVec max length.
234        #[pallet::constant]
235        type MaxAgentNameLengthConstraint: Get<u32>;
236
237        /// This is needed on agent::Agent to set the `url` field BoundedVec max
238        /// length.
239        #[pallet::constant]
240        type MaxAgentUrlLengthConstraint: Get<u32>;
241
242        #[pallet::constant]
243        type MaxAgentMetadataLengthConstraint: Get<u32>;
244
245        #[pallet::constant]
246        type DefaultDividendsParticipationWeight: Get<Percent>;
247
248        /// Default Cooldown (in blocks) in which an agent needs to wait between each `update_agent` call.
249        #[pallet::constant]
250        type DefaultAgentUpdateCooldown: Get<BlockNumberFor<Self>>;
251
252        #[pallet::constant]
253        type DefaultNamespacePricingConfig: Get<namespace::NamespacePricingConfig<Self>>;
254
255        type RuntimeEvent: From<Event<Self>>
256            + IsType<<Self as polkadot_sdk::frame_system::Config>::RuntimeEvent>;
257
258        type Currency: Currency<Self::AccountId, Balance = u128>
259            + ReservableCurrency<Self::AccountId>
260            + NamedReservableCurrency<Self::AccountId, ReserveIdentifier = [u8; 8]>
261            + Send
262            + Sync;
263        type ExistentialDeposit: Get<BalanceOf<Self>>;
264
265        type Governance: GovernanceApi<Self::AccountId>;
266
267        type Emission: Emission0Api<Self::AccountId>;
268        type Permission0: Permission0NamespacesApi<Self::AccountId, NamespacePath>
269            + Permission0WalletApi<Self::AccountId>;
270
271        type WeightInfo: WeightInfo;
272    }
273
274    #[pallet::pallet]
275    #[pallet::storage_version(STORAGE_VERSION)]
276    pub struct Pallet<T>(_);
277
278    #[pallet::call]
279    impl<T: Config> Pallet<T> {
280        /// Adds stakes from origin to the agent key.
281        #[pallet::call_index(0)]
282        #[pallet::weight((T::WeightInfo::add_stake(), DispatchClass::Normal, Pays::Yes))]
283        pub fn add_stake(
284            origin: OriginFor<T>,
285            agent_key: AccountIdOf<T>,
286            amount: BalanceOf<T>,
287        ) -> DispatchResult {
288            let key = ensure_signed(origin)?;
289            ensure!(
290                amount >= crate::MinAllowedStake::<T>::get(),
291                crate::Error::<T>::StakeTooSmall
292            );
293            stake::add_stake::<T>(key, agent_key, amount)
294        }
295
296        /// Removes stakes from origin to the agent key.
297        #[pallet::call_index(1)]
298        #[pallet::weight((T::WeightInfo::remove_stake(), DispatchClass::Normal, Pays::Yes))]
299        pub fn remove_stake(
300            origin: OriginFor<T>,
301            agent_key: AccountIdOf<T>,
302            amount: BalanceOf<T>,
303        ) -> DispatchResult {
304            let key = ensure_signed(origin)?;
305
306            ensure!(
307                !<T::Permission0>::find_active_wallet_permission(&key).any(|(_, perm)| {
308                    matches!(
309                        perm.r#type,
310                        WalletScopeType::Stake {
311                            exclusive_stake_access: true,
312                            ..
313                        }
314                    )
315                }),
316                Error::<T>::StakeIsDelegated
317            );
318
319            stake::remove_stake::<T>(key, agent_key, amount)
320        }
321
322        /// Transfers origin's stakes from an agent to another.
323        #[pallet::call_index(2)]
324        #[pallet::weight((T::WeightInfo::transfer_stake(), DispatchClass::Normal, Pays::Yes))]
325        pub fn transfer_stake(
326            origin: OriginFor<T>,
327            agent_key: AccountIdOf<T>,
328            new_agent_key: AccountIdOf<T>,
329            amount: BalanceOf<T>,
330        ) -> DispatchResult {
331            let key = ensure_signed(origin)?;
332
333            ensure!(
334                !<T::Permission0>::find_active_wallet_permission(&key).any(|(_, perm)| {
335                    matches!(
336                        perm.r#type,
337                        WalletScopeType::Stake {
338                            exclusive_stake_access: true,
339                            ..
340                        }
341                    )
342                }),
343                Error::<T>::StakeIsDelegated
344            );
345
346            stake::transfer_stake::<T>(key, agent_key, new_agent_key, amount)
347        }
348
349        /// Registers a new agent on behalf of an arbitrary key.
350        #[pallet::call_index(3)]
351        #[pallet::weight((T::WeightInfo::register_agent(), DispatchClass::Normal, Pays::Yes))]
352        pub fn register_agent(
353            origin: OriginFor<T>,
354            name: Vec<u8>,
355            url: Vec<u8>,
356            metadata: Vec<u8>,
357        ) -> DispatchResult {
358            let agent_key = ensure_signed(origin)?;
359            agent::register::<T>(agent_key, name, url, metadata)
360        }
361
362        /// Unregister origin's key agent.
363        #[pallet::call_index(4)]
364        #[pallet::weight((T::WeightInfo::deregister_agent(), DispatchClass::Normal, Pays::Yes))]
365        pub fn deregister_agent(origin: OriginFor<T>) -> DispatchResult {
366            let agent_key = ensure_signed(origin)?;
367            agent::deregister::<T>(agent_key)
368        }
369
370        /// Updates origin's key agent metadata.
371        #[pallet::call_index(5)]
372        #[pallet::weight((T::WeightInfo::update_agent(), DispatchClass::Normal, Pays::Yes))]
373        pub fn update_agent(
374            origin: OriginFor<T>,
375            url: Vec<u8>,
376            metadata: Option<Vec<u8>>,
377            staking_fee: Option<Percent>,
378            weight_control_fee: Option<Percent>,
379        ) -> DispatchResult {
380            let agent_key = ensure_signed(origin)?;
381            agent::update::<T>(agent_key, url, metadata, staking_fee, weight_control_fee)
382        }
383
384        /// Updates origin's key agent metadata.
385        #[pallet::call_index(6)]
386        #[pallet::weight((T::WeightInfo::set_agent_update_cooldown(), DispatchClass::Normal, Pays::Yes))]
387        pub fn set_agent_update_cooldown(
388            origin: OriginFor<T>,
389            new_cooldown: BlockNumberFor<T>,
390        ) -> DispatchResult {
391            ensure_root(origin)?;
392            AgentUpdateCooldown::<T>::set(new_cooldown);
393            Ok(())
394        }
395
396        /// Create a new namespace, automatically creating missing intermediate nodes
397        #[pallet::call_index(7)]
398        #[pallet::weight(Weight::default())]
399        pub fn create_namespace(origin: OriginFor<T>, path: NamespacePathInner) -> DispatchResult {
400            let owner = ensure_signed(origin)?;
401
402            ensure!(
403                <T as pallet::Config>::Governance::can_create_namespace(&owner),
404                Error::<T>::NamespacesFrozen
405            );
406
407            let namespace_path =
408                NamespacePath::new_agent(&path).map_err(|_| Error::<T>::InvalidNamespacePath)?;
409
410            namespace::create_namespace::<T>(NamespaceOwnership::Account(owner), namespace_path)
411        }
412
413        /// Delete a namespace and all its children
414        #[pallet::call_index(8)]
415        #[pallet::weight(Weight::default())]
416        pub fn delete_namespace(origin: OriginFor<T>, path: NamespacePathInner) -> DispatchResult {
417            let owner = ensure_signed(origin)?;
418
419            let namespace_path =
420                NamespacePath::new_agent(&path).map_err(|_| Error::<T>::InvalidNamespacePath)?;
421
422            ensure!(
423                !namespace_path.is_agent_root(),
424                Error::<T>::InvalidNamespacePath
425            );
426
427            namespace::delete_namespace::<T>(NamespaceOwnership::Account(owner), namespace_path)
428        }
429    }
430
431    #[pallet::event]
432    #[pallet::generate_deposit(pub fn deposit_event)]
433    pub enum Event<T: Config> {
434        /// Event created when stake has been transferred from the coldkey
435        /// account onto the key staking account
436        StakeAdded(AccountIdOf<T>, AccountIdOf<T>, BalanceOf<T>),
437        /// Event created when stake has been removed from the key staking
438        /// account onto the coldkey account
439        StakeRemoved(AccountIdOf<T>, AccountIdOf<T>, BalanceOf<T>),
440        /// Event created when a new agent account has been registered to the
441        /// chain
442        AgentRegistered(AccountIdOf<T>),
443        /// Event created when a agent account has been deregistered from the
444        /// chain
445        AgentUnregistered(AccountIdOf<T>),
446        /// Event created when the agent's updated information is added to the
447        /// network
448        AgentUpdated(AccountIdOf<T>),
449        /// Namespace created
450        NamespaceCreated {
451            owner: NamespaceOwnership<T>,
452            path: NamespacePath,
453        },
454        /// Namespace deleted
455        NamespaceDeleted {
456            owner: NamespaceOwnership<T>,
457            path: NamespacePath,
458        },
459    }
460
461    #[pallet::error]
462    pub enum Error<T> {
463        /// The specified agent does not exist.
464        AgentDoesNotExist,
465        /// Insufficient stake to withdraw the requested amount.
466        NotEnoughStakeToWithdraw,
467        /// Insufficient balance in the cold key account to stake the requested
468        /// amount.
469        NotEnoughBalanceToStake,
470        /// The number of agent registrations in this block exceeds the allowed
471        /// limit.
472        TooManyAgentRegistrationsThisBlock,
473        /// The number of agent registrations in this interval exceeds the
474        /// allowed limit.
475        TooManyAgentRegistrationsThisInterval,
476        /// The agent is already registered in the active set.
477        AgentAlreadyRegistered,
478        /// Failed to convert between u128 and T::Balance.
479        CouldNotConvertToBalance,
480        /// Failed to add balance to the account.
481        BalanceNotAdded,
482        /// Failed to remove stake from the account.
483        StakeNotRemoved,
484        /// Invalid shares distribution.
485        InvalidShares,
486        /// Insufficient balance to register.
487        NotEnoughBalanceToRegisterAgent,
488        /// Failed to add stake to the account.
489        StakeNotAdded,
490        /// Failed to remove balance from the account.
491        BalanceNotRemoved,
492        /// Balance could not be removed from the account.
493        BalanceCouldNotBeRemoved,
494        /// Insufficient stake to register.
495        NotEnoughStakeToRegister,
496        /// The entity is still registered and cannot be modified.
497        StillRegistered,
498        /// Insufficient balance to transfer.
499        NotEnoughBalanceToTransfer,
500        /// The agent metadata is invalid.
501        InvalidAgentMetadata,
502        /// The agent metadata is too long.
503        AgentMetadataTooLong,
504        /// The agent metadata is too long.
505        AgentMetadataTooShort,
506        /// The minimum burn value is invalid, likely too small.
507        InvalidMinBurn,
508        /// The maximum burn value is invalid.
509        InvalidMaxBurn,
510        /// The agent name is too long.
511        AgentNameTooLong,
512        /// The agent name is too short.
513        AgentNameTooShort,
514        /// The agent name is invalid. It must be a UTF-8 encoded string.
515        InvalidAgentName,
516        /// The agent url is too long.
517        AgentUrlTooLong,
518        /// The agent url is too short.
519        AgentUrlTooShort,
520        /// The agent ur; is invalid.
521        InvalidAgentUrl,
522        /// A agent with this name already exists in the subnet.
523        AgentNameAlreadyExists,
524        /// The stake amount to add or remove is too small. Minimum is 0.5 unit.
525        StakeTooSmall,
526        /// Key is not present in Whitelist, it needs to be whitelisted by a
527        /// Curator
528        AgentKeyNotWhitelisted,
529        /// The amount given is 0
530        InvalidAmount,
531        /// The staking fee given is lower than the minimum fee
532        InvalidStakingFee,
533        /// The weight control fee given is lower than the minimum fee
534        InvalidWeightControlFee,
535        /// The agent already updated recently
536        AgentUpdateOnCooldown,
537        /// Invalid namespace path
538        InvalidNamespacePath,
539        /// Namespace already exists
540        NamespaceAlreadyExists,
541        /// Namespace not found
542        NamespaceNotFound,
543        /// Parent namespace not found
544        ParentNamespaceNotFound,
545        /// Not the owner of the namespace
546        NotNamespaceOwner,
547        /// Cannot delete namespace with children
548        NamespaceHasChildren,
549        /// Namespace depth exceeded
550        NamespaceDepthExceeded,
551        /// The namespace is being delegated through a permission. Revoke that first.
552        NamespaceBeingDelegated,
553        /// Agent Creation was disabled by a curator.
554        AgentsFrozen,
555        /// Namespace Creation was disabled by a curator.
556        NamespacesFrozen,
557        /// The stake is being delegated exclusively.
558        StakeIsDelegated,
559    }
560}
561
562impl<T: Config>
563    pallet_torus0_api::Torus0Api<T::AccountId, <T::Currency as Currency<T::AccountId>>::Balance>
564    for Pallet<T>
565{
566    fn reward_interval() -> u16 {
567        RewardInterval::<T>::get()
568    }
569
570    fn min_validator_stake() -> u128 {
571        MinValidatorStake::<T>::get()
572    }
573
574    fn max_validators() -> u16 {
575        MaxAllowedValidators::<T>::get()
576    }
577
578    fn weight_control_fee(who: &T::AccountId) -> Percent {
579        Agents::<T>::get(who)
580            .map(|agent| agent.fees.weight_control_fee)
581            .unwrap_or_else(|| FeeConstraints::<T>::get().min_weight_control_fee)
582    }
583
584    fn weight_penalty_factor(who: &T::AccountId) -> Percent {
585        Agents::<T>::get(who)
586            .map(|agent| agent.weight_penalty_factor)
587            .unwrap_or_default()
588    }
589
590    fn staking_fee(who: &T::AccountId) -> Percent {
591        Agents::<T>::get(who)
592            .map(|agent| agent.fees.staking_fee)
593            .unwrap_or_else(|| FeeConstraints::<T>::get().min_staking_fee)
594    }
595
596    fn sum_staking_to(staker: &T::AccountId) -> BalanceOf<T> {
597        stake::sum_staking_to::<T>(staker)
598    }
599
600    fn staked_by(
601        staked: &T::AccountId,
602    ) -> sp_std::vec::Vec<(
603        T::AccountId,
604        <T::Currency as Currency<T::AccountId>>::Balance,
605    )> {
606        stake::get_staked_by_vector::<T>(staked)
607    }
608
609    fn stake_to(
610        staker: &T::AccountId,
611        staked: &T::AccountId,
612        amount: <T::Currency as Currency<T::AccountId>>::Balance,
613    ) -> DispatchResult {
614        stake::add_stake::<T>(staker.clone(), staked.clone(), amount)
615    }
616
617    fn remove_stake(
618        staker: &T::AccountId,
619        staked: &T::AccountId,
620        amount: <T::Currency as Currency<T::AccountId>>::Balance,
621    ) -> DispatchResult {
622        stake::remove_stake::<T>(staker.clone(), staked.clone(), amount)
623    }
624
625    fn transfer_stake(
626        staker: &T::AccountId,
627        from: &T::AccountId,
628        to: &T::AccountId,
629        amount: <T::Currency as Currency<T::AccountId>>::Balance,
630    ) -> DispatchResult {
631        stake::transfer_stake::<T>(staker.clone(), from.clone(), to.clone(), amount)
632    }
633
634    fn agent_ids() -> impl Iterator<Item = T::AccountId> {
635        Agents::<T>::iter_keys()
636    }
637
638    fn find_agent_by_name(name: &[u8]) -> Option<T::AccountId> {
639        Agents::<T>::iter()
640            .find(|(_, agent)| *agent.name == name)
641            .map(|(id, _)| id)
642    }
643
644    fn is_agent_registered(agent: &T::AccountId) -> bool {
645        Agents::<T>::contains_key(agent)
646    }
647
648    fn namespace_exists(agent: &T::AccountId, path: &NamespacePath) -> bool {
649        Namespaces::<T>::contains_key(NamespaceOwnership::Account(agent.clone()), path)
650    }
651
652    #[cfg(feature = "runtime-benchmarks")]
653    fn force_register_agent(
654        id: &T::AccountId,
655        name: Vec<u8>,
656        url: Vec<u8>,
657        metadata: Vec<u8>,
658    ) -> DispatchResult {
659        use pallet_torus0_api::NAMESPACE_AGENT_PREFIX;
660
661        crate::Agents::<T>::set(
662            id,
663            Some(Agent {
664                key: id.clone(),
665                name: name
666                    .clone()
667                    .try_into()
668                    .map_err(|_| DispatchError::Other("failed to trim fields"))?,
669                url: url
670                    .try_into()
671                    .map_err(|_| DispatchError::Other("failed to trim fields"))?,
672                metadata: metadata
673                    .try_into()
674                    .map_err(|_| DispatchError::Other("failed to trim fields"))?,
675                weight_penalty_factor: Default::default(),
676                registration_block: Default::default(),
677                fees: Default::default(),
678                last_update_block: Default::default(),
679            }),
680        );
681        Self::force_register_namespace(id, [NAMESPACE_AGENT_PREFIX, &name].concat()).unwrap();
682
683        Ok(())
684    }
685
686    #[cfg(feature = "runtime-benchmarks")]
687    fn force_register_namespace(id: &T::AccountId, name: Vec<u8>) -> DispatchResult {
688        let name = NamespacePath::new_agent(&name).map_err(|_| Error::<T>::InvalidNamespacePath)?;
689        #[allow(deprecated)]
690        namespace::create_namespace0(NamespaceOwnership::<T>::Account(id.clone()), name, false)
691    }
692
693    #[cfg(feature = "runtime-benchmarks")]
694    fn force_set_stake(
695        staker: &T::AccountId,
696        staked: &T::AccountId,
697        amount: BalanceOf<T>,
698    ) -> DispatchResult {
699        stake::add_stake::<T>(staker.clone(), staked.clone(), amount)
700    }
701}