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}