pallet_authors/
types.rs

1// SPDX-License-Identifier: MPL-2.0
2//
3// Part of Auguth Labs open-source softwares.
4// Built for the Substrate framework.
5//
6// This Source Code Form is subject to the terms of the Mozilla Public
7// License, v. 2.0. If a copy of the MPL was not distributed with this
8// file, You can obtain one at https://mozilla.org/MPL/2.0/.
9//
10// Copyright (c) 2026 Auguth Labs (OPC) Pvt Ltd, India
11
12// ===============================================================================
13// ```````````````````````````````` AUTHORS TYPES ````````````````````````````````
14// ===============================================================================
15
16//! **Core types and aliases for the Authors system.**
17//!
18//! This module defines the primary structures and type aliases used by
19//! [`pallet_authors`](crate). These types are publicly exposed and used across
20//! the pallet's APIs for representing Author-related data.
21//!
22//! Trait implementations provided by this crate's [`Pallet`] can use these types
23//! via trait-bound equality constraints to ensure type alignment with this pallet's
24//! concrete implementations if necessary.
25//!
26//! ## Example
27//!
28//! ```ignore
29//! mod pallet {
30//!     use pallet_authors::types::AuthorInfo;
31//!
32//!     pub trait Config: frame_system::Config {
33//!         type RoleAdapter: RoleManager<Meta = AuthorInfo<Self>>;
34//!     }
35//! }
36//! ```
37
38// ===============================================================================
39// ``````````````````````````````````` IMPORTS ```````````````````````````````````
40// ===============================================================================
41
42// --- Local crate imports ---
43use crate::{Config, Pallet};
44
45// --- Scale-codec crates ---
46use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
47use scale_info::TypeInfo;
48
49// --- Core / Std ---
50use core::{
51    cmp::Ordering,
52    fmt::{Debug, Formatter},
53};
54
55// --- FRAME Suite ---
56use frame_suite::{commitment::*, roles::*};
57
58// --- FRAME Support ---
59use frame_support::{
60    traits::{
61        tokens::{Fortitude, Precision},
62        VariantCount,
63    },
64    RuntimeDebugNoBound,
65};
66
67// --- FRAME System ---
68use frame_system::pallet_prelude::BlockNumberFor;
69
70// --- Substrate primitives ---
71use sp_core::RuntimeDebug;
72use sp_runtime::Vec;
73
74// ===============================================================================
75// ``````````````````````````````````` ALIASES ```````````````````````````````````
76// ===============================================================================
77
78/// Represents an on-chain account that can hold an `Author` role.
79pub type Author<T> = <T as frame_system::pallet::Config>::AccountId;
80
81/// Represents the **asset or balance type** associated with an `Author`
82/// in the context of funding, staking, or collateral.
83///
84/// Typically used for collateral management, reward calculation, and fund tracking.
85pub type AuthorAsset<T> = <<T as Config>::CommitmentAdapter as InspectAsset<Author<T>>>::Asset;
86
87/// Commission Type used by the Pallet for Pool Commissions.
88pub type Commission<T> = <<T as Config>::CommitmentAdapter as CommitPool<Author<T>>>::Commission;
89
90/// Penalty ratio type used by the Author Roles subsystem.
91pub type Ratio<T> = <Pallet<T> as CompensateRoles<Author<T>>>::Ratio;
92
93/// Shares Type used by the Pallet for Index/Pool shares.
94pub type Shares<T> = <<T as Config>::CommitmentAdapter as CommitIndex<Author<T>>>::Shares;
95
96/// Represents a cryptographic digest, a unique identifier for an `Author`.
97///
98/// Useful for referencing authors via commitments (funding) instead of
99/// its direct enrollment account IDs.
100pub type AuthorDigest<T> = <<T as Config>::CommitmentAdapter as Commitment<Author<T>>>::Digest;
101
102/// A list of authors selected by an election round.
103///
104/// Represents the final election output returned by the configured
105/// election model.
106pub type ElectedAuthors<T> = Vec<Author<T>>;
107
108/// Election input for **influence-based selection**.
109///
110/// Each entry pairs an [`Author`] with the influence values considered
111/// for that author during election.
112///
113/// Used by **flat election models** that operate on influence rather than
114/// individual funding relationships.
115pub type ElectViaInfluence<T> = Vec<(Author<T>, Vec<<T as Config>::Influence>)>;
116
117/// A single backing contribution used in **backing-based election**.
118///
119/// Pairs a [`Funder`] with the asset value attributed to that funder
120/// for election weighting.
121pub type BackingElectionWeight<T> = (Funder<T>, AuthorAsset<T>);
122
123/// Election input for **backing-based selection**.
124///
125/// Each entry pairs an [`Author`] with the backing contributions
126/// considered for that author during election.
127///
128/// Used by **fair election models** that preserve individual funder
129/// contributions instead of aggregating them into a single value.
130pub type ElectViaBacking<T> = Vec<(Author<T>, Vec<BackingElectionWeight<T>>)>;
131
132/// Represents a **digest identifier** for an indexed commitment (unmanaged pools)
133/// backing an [`Author`] role.
134pub type IndexDigest<T> = <<T as Config>::CommitmentAdapter as Commitment<Author<T>>>::Digest;
135
136/// Represents a **digest identifier** for a pool commitment (managed collective commitment)
137/// funding source for an [`Author`] role.
138pub type PoolDigest<T> = <<T as Config>::CommitmentAdapter as Commitment<Author<T>>>::Digest;
139
140/// Represents the account that provides backing to an [`Author`],
141/// either directly or through an index or pool funding mechanism.
142pub type Backer<T> = <T as frame_system::Config>::AccountId;
143
144// ===============================================================================
145// ````````````````````````````````` STRUCTURES ``````````````````````````````````
146// ===============================================================================
147
148/// Represents the **lifecycle state** of an `Author` role within the runtime.
149///
150/// This enum defines discrete states that an author (e.g., a block producer)
151/// can transition through during its lifecycle.
152///
153/// ## Decentralization Philosophy
154///
155/// The `Author` role deliberately **does not include a suspension state**.
156/// Instead of centralized or privileged suspension control, accountability
157/// is enforced through penalties only.
158///
159/// This ensures that the author ecosystem remains **decentralized and self-governing**,  
160/// avoiding unilateral suspension or authority over active participants.
161#[derive(
162    Encode,
163    Decode,
164    Clone,
165    PartialEq,
166    Eq,
167    RuntimeDebug,
168    MaxEncodedLen,
169    DecodeWithMemTracking,
170    TypeInfo,
171)]
172pub enum AuthorStatus {
173    /// The author is active and in good standing.
174    Active,
175
176    /// The author is temporarily under performance review or penalty watch.
177    ///
178    /// The author cannot resign while in this status to ensure accountability
179    /// until the probation period is resolved.
180    Probation,
181
182    /// The author has left the role, either voluntarily or by fulfilling
183    /// all obligations necessary for resignation.
184    Resigned,
185}
186
187/// Represents the **entity responsible for backing or funding** an [`Author`] role.
188///
189/// A `Funder` abstracts away different possible funding sources - individual accounts,
190/// indexed commitments, or pooled backing mechanisms - allowing the runtime to treat
191/// all funders uniformly.
192///
193/// ## Design Rationale
194///
195/// The `Funder` type enables **composable funding logic** by decoupling
196/// the origin of funds from their operational treatment.  
197/// Whether funds come directly from an account, a collective pool, or an
198/// indexing mechanism, they can all be processed consistently by the same logic.
199///
200/// ## Transparency
201///
202/// - Funding is open to multiple origins, encouraging *decentralized capital flow*.  
203/// - Digest-based identifiers ensure verifiable commitment integrity without
204///   requiring central registries.
205#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, Eq, MaxEncodedLen, TypeInfo)]
206#[scale_info(skip_type_params(T))]
207pub enum Funder<T: Config> {
208    /// A direct account-based funder (standard single backer).
209    Direct(Backer<T>),
210
211    /// An indexed commitment-based funder.
212    /// Contains the index's digest and the account through which it is backed.
213    Index {
214        /// Index Digest
215        digest: IndexDigest<T>,
216        /// Index's Backer/Funder
217        backer: Backer<T>,
218    },
219
220    /// A pool funder, representing collective or group-backed collateral.
221    /// Contains the pool's digest and the account through which it is backed.
222    Pool {
223        /// Pool Digest
224        digest: PoolDigest<T>,
225        /// Pool's Backer/Funder
226        backer: Backer<T>,
227    },
228}
229
230/// Represents the **on-chain record of an [`Author`] role** within the runtime.
231///
232/// This struct captures all essential metadata for managing an author's lifecycle,
233/// funding, and status.
234///
235/// ## Design Rationale
236///
237/// - **Lifecycle tracking:** `since`, `stale_since`, and `frozen_until` allow the
238///   runtime to enforce penalties,
239///   rewards, or inactivity handling without central authority.
240/// - **Decentralization:** No suspension logic is provided; accountability is
241///   enforced through penalties and voluntary resignation.
242/// - **Composability:** `funders` is a bounded collection of [`Funder`], allowing
243///   flexible funding models (direct, index, or pool).
244/// - **Auditability:** All timestamps and digests provide verifiable on-chain evidence
245///   of the author's role state.
246#[derive(Encode, Decode, PartialEq, Eq, Clone, MaxEncodedLen, TypeInfo, DecodeWithMemTracking)]
247#[scale_info(skip_type_params(T))]
248pub struct AuthorInfo<T: Config> {
249    /// Unique commitment digest/hash or derived identifier for the author
250    /// (not the author's accountId).
251    pub digest: AuthorDigest<T>,
252
253    /// Timestamp when the author was enrolled.
254    pub since: BlockNumberFor<T>,
255
256    /// Current status of the author.
257    pub status: AuthorStatus,
258
259    /// Timestamp when the author status was updated.
260    pub status_since: BlockNumberFor<T>,
261
262    /// Timestamp until which the author is at risk to the system.
263    ///
264    /// This indicates, that till this time the author cannot
265    /// do few runtime actions.
266    ///
267    /// If in the past, the author is considered safe.
268    pub risk_until: BlockNumberFor<T>,
269
270    /// Locally defined minimum fund to support this author.
271    pub min_fund: Option<AuthorAsset<T>>,
272
273    /// Locally defined maximum fund exposure for this author.
274    pub max_fund: Option<AuthorAsset<T>>,
275}
276
277/// Specifies the destination or mechanism by which funds are allocated
278/// within the authors / roles system.
279///
280/// A `FundingTarget` determines *how* a contribution is routed:
281/// - directly to a single author,
282/// - indirectly via an index abstraction,
283/// - or pooled into a shared funding vehicle.
284///
285/// This enum is used by funding and compensation logic to resolve
286/// the final recipients and exposure semantics of a funding action.
287#[derive(
288    Encode,
289    Decode,
290    DecodeWithMemTracking,
291    RuntimeDebugNoBound,
292    Clone,
293    PartialEq,
294    Eq,
295    MaxEncodedLen,
296    TypeInfo,
297)]
298#[scale_info(skip_type_params(T))]
299pub enum FundingTarget<T: Config> {
300    /// Funds are allocated directly to a specific author.
301    Direct(Author<T>),
302
303    /// Funds are allocated via an index abstraction.
304    Index(IndexDigest<T>),
305
306    /// Funds are allocated into a shared funding pool.
307    Pool(PoolDigest<T>),
308}
309
310/// Enumerates configurable runtime-stored parameters that
311/// influences probation, rewards, penalties, election constraints,
312/// or economic limits may be forcibly overridden
313/// at runtime through privileged (root/governance) operations.
314#[derive(
315    Encode,
316    Decode,
317    DecodeWithMemTracking,
318    RuntimeDebugNoBound,
319    Clone,
320    PartialEq,
321    Eq,
322    MaxEncodedLen,
323    TypeInfo,
324)]
325#[scale_info(skip_type_params(T))]
326pub enum ForceGenesisConfig<T: Config> {
327    /// Updates the number of blocks authors must remain in probation.
328    ProbationPeriod(BlockNumberFor<T>),
329    /// Updates how much probation is reduced on good behavior.
330    ReduceProbationBy(BlockNumberFor<T>),
331    /// Updates how much probation is increased on misbehavior.
332    IncreaseProbationBy(BlockNumberFor<T>),
333    // Updates the delay (in blocks) before rewards are finalized.
334    RewardsBuffer(BlockNumberFor<T>),
335    /// Updates the delay (in blocks) before penalties are enforced.
336    PenaltiesBuffer(BlockNumberFor<T>),
337    /// Updates the maximum number of authors that can be elected.
338    MaxElected(u32),
339    /// Updates the minimum number of authors required for a valid election.
340    MinElected(u32),
341    /// Toggles strict enforcement of `MaxElected`.
342    EnforceMaxElected(bool),
343    /// Update the  minimum funding required per backing operation.
344    MinFund(AuthorAsset<T>),
345    /// Updates the maximum allowed exposure per funding operation.
346    MaxExposure(AuthorAsset<T>),
347    /// Updates the minimum collateral required for authors.
348    MinCollateral(AuthorAsset<T>),
349}
350
351/// Wrapper type for [`Fortitude`] used in extrinsics.
352///
353/// ## Variants
354/// - `Force`: Enforces the operation strictly, potentially overriding
355///   softer constraints or preferences.
356/// - `Polite`: Applies the operation in a non-strict manner, respecting
357///   constraints and failing if conditions are not ideal.
358///
359/// ## Notes
360/// - This type exists to decouple the extrinsic API from the internal
361///   [`Fortitude`] type.
362/// - It is converted into [`Fortitude`] internally before execution.
363#[derive(
364    Encode,
365    Decode,
366    DecodeWithMemTracking,
367    RuntimeDebugNoBound,
368    Clone,
369    PartialEq,
370    Eq,
371    MaxEncodedLen,
372    TypeInfo,
373)]
374pub enum FortitudeWrapper {
375    Force,
376    Polite,
377}
378
379/// Wrapper type for [`Precision`] used in extrinsics.
380///
381/// This enum defines how precisely a funding operation should be executed,
382/// particularly in scenarios where exact amounts may not be achievable due
383/// to rounding, liquidity, or distribution constraints.
384///
385/// ## Variants
386/// - `Exact`: Requires the operation to be executed with exact precision.
387///   Fails if the exact value cannot be honored.
388/// - `BestEffort`: Allows approximate execution, where the system will
389///   attempt to fulfill the request as closely as possible.
390///
391/// ## Notes
392/// - This type exists to decouple the extrinsic API from the internal
393///   [`Precision`] type.
394/// - It is converted into [`Precision`] internally before execution.
395#[derive(
396    Encode,
397    Decode,
398    DecodeWithMemTracking,
399    RuntimeDebugNoBound,
400    Clone,
401    PartialEq,
402    Eq,
403    MaxEncodedLen,
404    TypeInfo,
405)]
406pub enum PrecisionWrapper {
407    Exact,
408    BestEffort,
409}
410
411// ===============================================================================
412// ```````````````````````````````` INHERENT IMPLS ```````````````````````````````
413// ===============================================================================
414
415impl<T: Config> AuthorInfo<T> {
416    /// Creates a new `AuthorInfo` instance with default timestamps and status.
417    ///
418    /// - `status` starts as `Probation` to ensure initial monitoring and enforces
419    ///    probation period.
420    /// - `since`, `stale_since`, and `risk_until` are set to the current block number.
421    pub fn new(digest: AuthorDigest<T>) -> Self {
422        let current_block = frame_system::Pallet::<T>::block_number();
423        Self {
424            digest,
425            since: current_block,
426            status: AuthorStatus::Probation,
427            status_since: current_block,
428            risk_until: current_block,
429            min_fund: None,
430            max_fund: None,
431        }
432    }
433
434    /// Recreates the author state for re-enrollment.
435    ///
436    /// - Resets lifecycle timestamps to the current block.
437    /// - Sets status to `Probation` for re-evaluation.
438    /// - Clears local funding constraints (`min_fund`, `max_fund`).
439    /// - Retains the existing commitment digest.
440    pub fn re_enroll(&self) -> Self {
441        let current_block = frame_system::Pallet::<T>::block_number();
442        Self {
443            digest: self.digest.clone(),
444            since: current_block,
445            status: AuthorStatus::Probation,
446            status_since: current_block,
447            risk_until: current_block,
448            min_fund: None,
449            max_fund: None,
450        }
451    }
452}
453
454// ===============================================================================
455// ````````````````````````````````` TRAIT IMPLS `````````````````````````````````
456// ===============================================================================
457
458impl VariantCount for AuthorStatus {
459    /// The number of distinct variants for [`AuthorStatus`].
460    const VARIANT_COUNT: u32 = 3;
461}
462
463impl From<PrecisionWrapper> for Precision {
464    fn from(value: PrecisionWrapper) -> Self {
465        match value {
466            PrecisionWrapper::Exact => Precision::Exact,
467            PrecisionWrapper::BestEffort => Precision::BestEffort,
468        }
469    }
470}
471
472impl From<FortitudeWrapper> for Fortitude {
473    fn from(value: FortitudeWrapper) -> Self {
474        match value {
475            FortitudeWrapper::Force => Fortitude::Force,
476            FortitudeWrapper::Polite => Fortitude::Polite,
477        }
478    }
479}
480
481// ===============================================================================
482// ````````````````````````````````` DERIVE IMPLS ````````````````````````````````
483// ===============================================================================
484
485impl<T: Config> Debug for Funder<T> {
486    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
487        match self {
488            Funder::Direct(d) => write!(f, "Direct({:?})", d),
489            Funder::Index { digest, backer } => {
490                write!(f, "Index(digest: {:?}, backer: {:?})", digest, backer)
491            }
492            Funder::Pool { digest, backer } => {
493                write!(f, "Pool(digest: {:?}, backer: {:?})", digest, backer)
494            }
495        }
496    }
497}
498
499/// [`BackingElectionWeight`] tuple only takes the other element [`AuthorAsset`] for ordering.
500impl<T: Config> Ord for Funder<T> {
501    fn cmp(&self, _other: &Self) -> Ordering {
502        Ordering::Equal
503    }
504}
505
506impl<T: Config> PartialOrd for Funder<T> {
507    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
508        Some(self.cmp(other))
509    }
510}
511
512impl<T: Config> core::fmt::Debug for AuthorInfo<T> {
513    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
514        f.debug_struct("AuthorInfo")
515            .field("digest", &self.digest)
516            .field("since", &self.since)
517            .field("status", &self.status)
518            .field("status_since", &self.status_since)
519            .field("risk_until", &self.risk_until)
520            .field("min_fund", &self.min_fund)
521            .field("max_fund", &self.max_fund)
522            .finish()
523    }
524}