pallet_time_release/
types.rs

1//! Types for the TimeRelease Pallet
2#![cfg_attr(not(feature = "std"), no_std)]
3
4use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode, HasCompact, MaxEncodedLen};
5use sp_runtime::{traits::AtLeast32Bit, DispatchError, RuntimeDebug};
6extern crate alloc;
7use alloc::boxed::Box;
8use core::cmp::{Eq, PartialEq};
9
10use scale_info::TypeInfo;
11
12/// Alias for a schedule identifier
13pub type ScheduleName = [u8; 32];
14
15/// The release schedule.
16///
17/// Benefits would be granted gradually, `per_period` amount every `period`
18/// of blocks after `start`.
19#[derive(
20	Clone,
21	Encode,
22	Decode,
23	DecodeWithMemTracking,
24	PartialEq,
25	Eq,
26	RuntimeDebug,
27	MaxEncodedLen,
28	TypeInfo,
29)]
30pub struct ReleaseSchedule<BlockNumber, Balance>
31where
32	Balance: MaxEncodedLen + HasCompact,
33{
34	/// Vesting starting block
35	pub start: BlockNumber,
36	/// Number of blocks between vest
37	pub period: BlockNumber,
38	/// Number of vest
39	pub period_count: u32,
40	/// Amount of tokens to release per vest
41	#[codec(compact)]
42	pub per_period: Balance,
43}
44
45impl<BlockNumber: AtLeast32Bit + Copy, Balance: AtLeast32Bit + MaxEncodedLen + Copy>
46	ReleaseSchedule<BlockNumber, Balance>
47{
48	/// Returns the end of all periods, `None` if calculation overflows.
49	pub fn end(&self) -> Option<BlockNumber> {
50		// period * period_count + start
51		self.period.checked_mul(&self.period_count.into())?.checked_add(&self.start)
52	}
53
54	/// Returns all frozen amount, `None` if calculation overflows.
55	pub fn total_amount(&self) -> Option<Balance> {
56		self.per_period.checked_mul(&self.period_count.into())
57	}
58
59	/// Returns frozen amount for a given `time`.
60	///
61	/// Note this func assumes schedule is a valid one(non-zero period and
62	/// non-overflow total amount), and it should be guaranteed by callers.
63	#[allow(clippy::expect_used)]
64	pub fn frozen_amount(&self, time: BlockNumber) -> Balance {
65		// full = (time - start) / period
66		// unrealized = period_count - full
67		// per_period * unrealized
68		let full = time
69			.saturating_sub(self.start)
70			.checked_div(&self.period)
71			.expect("ensured non-zero period; qed");
72		let unrealized = self.period_count.saturating_sub(full.unique_saturated_into());
73		self.per_period
74			.checked_mul(&unrealized.into())
75			.expect("ensured non-overflow total amount; qed")
76	}
77}
78
79/// A trait that defines a scheduler provider for scheduling calls to be executed at a specific block number.
80pub trait SchedulerProviderTrait<Origin, BlockNumber, Call> {
81	/// Schedules a call to be executed at a specified block number.
82	///
83	/// # Returns
84	/// - `Ok(())` if the call was successfully scheduled.
85	/// - `Err(DispatchError)` if there was an error scheduling the call.
86	///
87	/// # Errors
88	/// This function may return a `DispatchError` for various reasons, such as:
89	/// - Insufficient permissions or invalid origin.
90	/// - Invalid block number or scheduling conflicts.
91	/// - Other runtime-specific errors.
92	fn schedule(
93		origin: Origin,
94		id: ScheduleName,
95		when: BlockNumber,
96		call: Box<Call>,
97	) -> Result<(), DispatchError>;
98
99	/// Cancels a scheduled call with an specific schedule-name.
100	///
101	/// # Returns
102	/// - `Ok(())` if the call was successfully canceled.
103	/// - `Err(DispatchError)` if there was an error canceling the call.
104	fn cancel(origin: Origin, id: ScheduleName) -> Result<(), DispatchError>;
105}