pub struct PiecewisePayout;Expand description
The PiecewisePayout model computes rewards using a piecewise-defined function, selecting different behaviors depending on the input range.
Concept: Segmented Reward Function
§Formula
reward(x) = f_i(x), for the first segment i where x is in [start_x_i, end_x_i]
0, if no segment matches§Segment Types
- Linear:
y = start_y + t * (end_y - start_y)wheret = (x - x1) / (x2 - x1). Supports both increasing and decreasing slopes for signed and unsigned types. - Curve:
y = L / (1 + e^(-k*(x - x0))). Works correctly for unsigned types; signed arithmetic handled viaFixedI128.
§Signed Arithmetic
Two sub-computations require signed intermediates that unsigned fixed-point cannot represent:
- Curve segments:
x - x0is negative forx < x0(the left sigmoid tail). The old code clamped this to 0 via unsignedsaturating_sub, flattening the entire left half of every curve segment. - Decreasing linear segments:
end_y - start_yis negative whenend_y < start_y. The old code clamped to 0, turning every ramp-down into a flat line.
Both are now computed in concrete FixedI128 via FixedSignedCast.
§Characteristics:
- Composable: Combine Linear and Curve segments freely.
- Works with unsigned types: No
Negbound, signed arithmetic inFixedI128. - Deterministic: Same input and configuration yield identical output.
- Context-driven: Controlled via
PiecewiseConfig.
§Applications:
- Multi-phase emission schedules.
- Bootstrap, growth, and stabilization curves.
- DeFi incentive design.
- Tiered reward systems.
§Example
// Linear ramp: x in [0, 10] maps reward from 0 to 100.
let config = PiecewiseConfig {
segments: vec![
Segment::Linear {
start_x: FixedU128::zero(),
end_x: FixedU128::saturating_from_integer(10),
start_y: FixedU128::zero(),
end_y: FixedU128::saturating_from_integer(100),
}
],
};
assert_eq!(PiecewisePayout::compute(5u128, Some(config)), 50);Trait Implementations§
Source§impl Debug for PiecewisePayout
impl Debug for PiecewisePayout
Source§impl Default for PiecewisePayout
impl Default for PiecewisePayout
Source§fn default() -> PiecewisePayout
fn default() -> PiecewisePayout
Source§impl<FixedPoint, Asset> PurePluginModel<Asset, PiecewiseConfig<FixedPoint>, Asset> for PiecewisePayoutwhere
Asset: Copy + IntegerToFixed + FixedForInteger<FixedPoint = FixedPoint> + Zero,
FixedPoint: FixedPointNumber + FixedSignedCast<Signed = FixedI128>,
impl<FixedPoint, Asset> PurePluginModel<Asset, PiecewiseConfig<FixedPoint>, Asset> for PiecewisePayoutwhere
Asset: Copy + IntegerToFixed + FixedForInteger<FixedPoint = FixedPoint> + Zero,
FixedPoint: FixedPointNumber + FixedSignedCast<Signed = FixedI128>,
Source§fn compute(&self, input: Asset, context: &PiecewiseConfig<FixedPoint>) -> Asset
fn compute(&self, input: Asset, context: &PiecewiseConfig<FixedPoint>) -> Asset
Auto Trait Implementations§
impl Freeze for PiecewisePayout
impl RefUnwindSafe for PiecewisePayout
impl Send for PiecewisePayout
impl Sync for PiecewisePayout
impl Unpin for PiecewisePayout
impl UnwindSafe for PiecewisePayout
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> CheckedConversion for T
impl<T> CheckedConversion for T
§fn checked_from<T>(t: T) -> Option<Self>where
Self: TryFrom<T>,
fn checked_from<T>(t: T) -> Option<Self>where
Self: TryFrom<T>,
§fn checked_into<T>(self) -> Option<T>where
Self: TryInto<T>,
fn checked_into<T>(self) -> Option<T>where
Self: TryInto<T>,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T, U, Tag> IntoTag<U, Tag> for Twhere
U: FromTag<T, Tag>,
Tag: DiscriminantTag,
impl<T, U, Tag> IntoTag<U, Tag> for Twhere
U: FromTag<T, Tag>,
Tag: DiscriminantTag,
§impl<Src, Dest> IntoTuple<Dest> for Srcwhere
Dest: FromTuple<Src>,
impl<Src, Dest> IntoTuple<Dest> for Srcwhere
Dest: FromTuple<Src>,
fn into_tuple(self) -> Dest
§impl<T> IsType<T> for T
impl<T> IsType<T> for T
§impl<T, Outer> IsWrappedBy<Outer> for T
impl<T, Outer> IsWrappedBy<Outer> for T
Source§impl<T, Time> Logging<Time> for Twhere
Time: Time,
impl<T, Time> Logging<Time> for Twhere
Time: Time,
Source§const FALLBACK_TARGET: &'static str = "routine"
const FALLBACK_TARGET: &'static str = "routine"
Default logging target if none is provided.
Most routines, especially offchain workers or background tasks, use this target for simplicity.
It allows a consistent place to look for routine logs without requiring every call to specify a target.
Note: This target is only a conveninence and may be somewhat vague. To ensure errors can still be traced accurately, the logged messages should include additional metadata (e.g., module name, error index, or contextual info) so that the source of the error can be identified even if the target is generic.
Source§type Logger = DispatchError
type Logger = DispatchError
The type taken and returned for logging.
We simply return the same [DispatchError] that was logged,
so logging does not change control flow or error propagation.
DispatchError is used because in Substrate it encompasses all
runtime errors - including module errors, token errors, arithmetic
issues, and transactional boundaries - making it the universal
substrate-side error representation.
Source§type Level = LogLevel
type Level = LogLevel
The log level type.
We use the LogLevel enum to standardize severity levels
(Info, Warn, Error, Debug) across all routine logs.
Source§fn log(
level: <T as Logging<Time>>::Level,
err: &<T as Logging<Time>>::Logger,
timestamp: Time,
target: Option<&str>,
fmt: Option<fn(Time, &<T as Logging<Time>>::Level, &str, &str) -> String>,
) -> <T as Logging<Time>>::Logger
fn log( level: <T as Logging<Time>>::Level, err: &<T as Logging<Time>>::Logger, timestamp: Time, target: Option<&str>, fmt: Option<fn(Time, &<T as Logging<Time>>::Level, &str, &str) -> String>, ) -> <T as Logging<Time>>::Logger
Source§fn info(
err: &Self::Logger,
timestamp: Timestamp,
target: Option<&str>,
fmt: Option<fn(Timestamp, &Self::Level, &str, &str) -> String>,
) -> Self::Loggerwhere
Self: Sized,
fn info(
err: &Self::Logger,
timestamp: Timestamp,
target: Option<&str>,
fmt: Option<fn(Timestamp, &Self::Level, &str, &str) -> String>,
) -> Self::Loggerwhere
Self: Sized,
Source§fn warn(
err: &Self::Logger,
timestamp: Timestamp,
target: Option<&str>,
fmt: Option<fn(Timestamp, &Self::Level, &str, &str) -> String>,
) -> Self::Loggerwhere
Self: Sized,
fn warn(
err: &Self::Logger,
timestamp: Timestamp,
target: Option<&str>,
fmt: Option<fn(Timestamp, &Self::Level, &str, &str) -> String>,
) -> Self::Loggerwhere
Self: Sized,
§impl<T> SaturatedConversion for T
impl<T> SaturatedConversion for T
§fn saturated_from<T>(t: T) -> Selfwhere
Self: UniqueSaturatedFrom<T>,
fn saturated_from<T>(t: T) -> Selfwhere
Self: UniqueSaturatedFrom<T>,
§fn saturated_into<T>(self) -> Twhere
Self: UniqueSaturatedInto<T>,
fn saturated_into<T>(self) -> Twhere
Self: UniqueSaturatedInto<T>,
T. Read more§impl<T, U> TryIntoKey<U> for Twhere
U: TryFromKey<T>,
impl<T, U> TryIntoKey<U> for Twhere
U: TryFromKey<T>,
type Error = <U as TryFromKey<T>>::Error
fn try_into_key(self) -> Result<U, <U as TryFromKey<T>>::Error>
§impl<S, T> UncheckedInto<T> for Swhere
T: UncheckedFrom<S>,
impl<S, T> UncheckedInto<T> for Swhere
T: UncheckedFrom<S>,
§fn unchecked_into(self) -> T
fn unchecked_into(self) -> T
unchecked_from.§impl<T, S> UniqueSaturatedInto<T> for S
impl<T, S> UniqueSaturatedInto<T> for S
§fn unique_saturated_into(self) -> T
fn unique_saturated_into(self) -> T
T.