Skip to content

Commit cfd6b28

Browse files
authored
chore: documentation for curve module (#801)
adds some docs for the curve module.
1 parent 8e44a7a commit cfd6b28

File tree

4 files changed

+205
-0
lines changed

4 files changed

+205
-0
lines changed

pallets/pallet-bonded-coins/src/curves/lmsr.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,33 @@
1+
/// Implementation of the [Logarithmic Market Scoring Rule (LMSR)](https://mason.gmu.edu/~rhanson/mktscore.pdf) bonding curve.
2+
///
3+
/// This module provides an LMSR bonding curve implementation, which determines the cost of purchasing
4+
/// assets based on the liquidity parameter and the current supply of assets in the market.
5+
///
6+
/// ### Cost Function
7+
/// The LMSR bonding curve is defined by the equation:
8+
/// ```text
9+
/// C(s) = m * ln(Σ(e^(s_i / m)))
10+
/// ```
11+
/// Where:
12+
/// - `s` is the supply of all assets, represented as a vector,
13+
/// - `m` is the liquidity parameter of the LMSR model,
14+
/// - `s_i` is the supply of a single asset.
15+
///
16+
/// `C(s)` represents the accumulated cost of purchasing or selling assets up to the current supply `s`.
17+
///
18+
/// ### Incremental Cost
19+
/// To calculate the incremental cost of a transaction, use the formula:
20+
/// ```text
21+
/// Incremental Cost = C(s) - C(s*)
22+
/// ```
23+
/// Here:
24+
/// - `s*` is the supply of assets in the market before the transaction, and
25+
/// - `s` is the supply of assets after the transaction.
26+
///
27+
/// ### Optimization for Numerical Stability
28+
/// To ensure numerical stability and prevent overflow/underflow during calculations,
29+
/// this implementation uses the [log-sum-exp trick](https://en.wikipedia.org/wiki/LogSumExp).
30+
/// This technique improves precision when handling the summation and exponential terms in the cost function.
131
use frame_support::ensure;
232
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
333
use scale_info::TypeInfo;
@@ -11,16 +41,26 @@ use substrate_fixed::{
1141
use super::BondingFunction;
1242
use crate::{PassiveSupply, Precision, LOG_TARGET};
1343

44+
/// A struct representing the unchecked input parameters for the LMSR model. This struct is used to convert
45+
/// the input parameters to the correct fixed-point type.
1446
#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
1547
pub struct LMSRParametersInput<Parameter> {
48+
/// The liquidity parameter for the LMSR model
1649
pub m: Parameter,
1750
}
1851

52+
/// A struct representing the validated parameters for the LMSR model. This struct is used to store the
53+
/// parameters for the LMSR model and to perform calculations using the LMSR model.
1954
#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
2055
pub struct LMSRParameters<Parameter> {
56+
///The liquidity parameter for the LMSR model. This value must be greater than zero and unsigned.
2157
pub m: Parameter,
2258
}
2359

60+
/// Implementation of the TryFrom trait for `LMSRParametersInput` to convert the input parameters to
61+
/// the correct fixed-point type. The TryFrom implementation for `LMSRParameters` will fail if the
62+
/// conversion to the fixed-point type fails or if the liquidity parameter is less than or equal to
63+
/// zero.
2464
impl<I: FixedUnsigned, C: FixedSigned> TryFrom<LMSRParametersInput<I>> for LMSRParameters<C> {
2565
type Error = ();
2666
fn try_from(value: LMSRParametersInput<I>) -> Result<Self, Self::Error> {
@@ -35,6 +75,8 @@ where
3575
Parameter: FixedSigned + PartialOrd<Precision> + From<Precision> + ToFixed,
3676
<Parameter as Fixed>::Bits: Copy + ToFixed + AddAssign + BitOrAssign + ShlAssign,
3777
{
78+
/// Calculate the logarithmic sum of the exponentials of the supply values,
79+
/// using the log-sum-exp trick.
3880
fn lse(&self, supply: &[Parameter]) -> Result<Parameter, ArithmeticError> {
3981
// Find the maximum value in the supply for numerical stability
4082
let max = supply.iter().max().ok_or_else(|| {
@@ -67,6 +109,7 @@ where
67109
Parameter: FixedSigned + PartialOrd<Precision> + From<Precision> + ToFixed,
68110
<Parameter as Fixed>::Bits: Copy + ToFixed + AddAssign + BitOrAssign + ShlAssign,
69111
{
112+
/// Calculate the cost of purchasing a set of assets from the market using the LMSR model.
70113
fn calculate_costs(
71114
&self,
72115
low: Parameter,

pallets/pallet-bonded-coins/src/curves/mod.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
/// Curve Module
2+
///
3+
/// This module defines various curve types and their associated parameters used in the system.
4+
/// It includes the following curve types:
5+
/// - Polynomial
6+
/// - SquareRoot
7+
/// - LMSR (Logarithmic Market Scoring Rule)
18
pub(crate) mod lmsr;
29
pub(crate) mod polynomial;
310
pub(crate) mod square_root;
@@ -19,20 +26,29 @@ use crate::{
1926
Config, CurveParameterTypeOf, PassiveSupply, Precision,
2027
};
2128

29+
/// An enum representing different types of curves with their respective parameters.
30+
/// Used to store curve parameters and perform calculations.
2231
#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
2332
pub enum Curve<Parameter> {
2433
Polynomial(PolynomialParameters<Parameter>),
2534
SquareRoot(SquareRootParameters<Parameter>),
2635
Lmsr(LMSRParameters<Parameter>),
2736
}
2837

38+
/// An enum representing input parameters for different types of curves.
39+
/// Used to convert into Curve.
2940
#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
3041
pub enum CurveInput<Parameter> {
3142
Polynomial(PolynomialParametersInput<Parameter>),
3243
SquareRoot(SquareRootParametersInput<Parameter>),
3344
Lmsr(LMSRParametersInput<Parameter>),
3445
}
3546

47+
/// Implementation of the TryFrom trait for `CurveInput` to convert the input parameters to
48+
/// the correct fixed-point type. The TryFrom implementation for `Curve` will fail if the
49+
/// conversion to the fixed-point type fails.
50+
/// The conversion is done by converting the input parameters to the correct fixed-point type
51+
/// using the TryFrom implementation for the respective parameters type.
3652
impl<I, C> TryFrom<CurveInput<I>> for Curve<C>
3753
where
3854
LMSRParameters<C>: TryFrom<LMSRParametersInput<I>>,
@@ -72,6 +88,10 @@ where
7288
}
7389
}
7490

91+
/// Implementation of the `BondingFunction` trait for `Curve`.
92+
/// The `BondingFunction` trait is used to calculate the cost of purchasing or selling assets using the curve.
93+
///
94+
/// The implementation forwards the call to the inner bonding function.
7595
impl<Parameter> BondingFunction<Parameter> for Curve<Parameter>
7696
where
7797
Parameter: FixedSigned + PartialOrd<Precision> + From<Precision> + ToFixed,
@@ -87,6 +107,14 @@ where
87107
}
88108
}
89109

110+
/// Trait defining the bonding function for a curve.
111+
/// The bonding function is used to calculate the cost of purchasing or selling assets using the curve.
112+
/// The trait is implemented for each curve type.
113+
///
114+
/// Parameters:
115+
/// - `low`: The lower bound of integral.
116+
/// - `high`: The upper bound of integral.
117+
/// - `passive_supply`: The passive supply of other assets in the pool, which are not affected by the operation.
90118
pub trait BondingFunction<Balance> {
91119
fn calculate_costs(
92120
&self,
@@ -96,16 +124,19 @@ pub trait BondingFunction<Balance> {
96124
) -> Result<Balance, ArithmeticError>;
97125
}
98126

127+
/// Helper function to calculate the square of a fixed-point number.
99128
fn square<FixedType: Fixed>(x: FixedType) -> Result<FixedType, ArithmeticError> {
100129
x.checked_mul(x).ok_or(ArithmeticError::Overflow)
101130
}
102131

132+
/// Helper function to calculate the accumulated passive issuance.
103133
fn calculate_accumulated_passive_issuance<Balance: Fixed>(passive_issuance: &[Balance]) -> Balance {
104134
passive_issuance
105135
.iter()
106136
.fold(Balance::from_num(0), |sum, x| sum.saturating_add(*x))
107137
}
108138

139+
/// TODO. Implementation might change.
109140
pub(crate) fn convert_to_fixed<T: Config>(x: u128, denomination: u8) -> Result<CurveParameterTypeOf<T>, ArithmeticError>
110141
where
111142
<CurveParameterTypeOf<T> as Fixed>::Bits: TryFrom<U256>, // TODO: make large integer type configurable in runtime

pallets/pallet-bonded-coins/src/curves/polynomial.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,44 @@
1+
/// Polynomial Bonding Curve Implementation.
2+
///
3+
/// This module provides an implementation of a polynomial bonding curve.
4+
/// The current implementation supports a polynomial function of order 2, with the integral precomputed for efficiency.
5+
///
6+
/// ### Cost Function
7+
/// The cost function is defined as:
8+
/// ```text
9+
/// c(s) = m * s^2 + n * s + o
10+
/// ```
11+
/// This function, `c(s)`, determines the price for purchasing or selling assets at any supply point `s`.
12+
/// The total cost of transactions is computed as the integral of `c(s)` between the start point and `s`.
13+
///
14+
/// ### Antiderivative
15+
/// The indefinite integral of the cost function is:
16+
/// ```text
17+
/// C(s) = (m / 3) * s^3 + (n / 2) * s^2 + o * s
18+
/// ```
19+
/// Where:
20+
/// - `m` is the coefficient for the quadratic term,
21+
/// - `n` is the coefficient for the linear term,
22+
/// - `o` is the constant term.
23+
///
24+
///
25+
/// `C(s)` represents the accumulated cost of purchasing or selling assets up to the current supply `s`.
26+
/// The integral between two supply points, `s*` (initial supply) and `s` (current supply), gives the incremental cost:
27+
/// ```text
28+
/// Incremental Cost = C(s) - C(s*)
29+
/// ```
30+
/// This captures the total cost for changing the supply from `s*` to `s`.
31+
///
32+
/// ### Optimization for Numerical Stability
33+
/// The computation of `s^3` can cause overflow in fixed-point arithmetic. To mitigate this, the calculation is factored as:
34+
/// ```text
35+
/// x^3 - y^3 = (x^2 + x * y + y^2) * (x - y)
36+
/// ```
37+
/// Where:
38+
/// - `x` is the upper limit of the integral,
39+
/// - `y` is the lower limit of the integral.
40+
///
41+
/// By breaking down the computation in this way, we reduce the risk of overflow while maintaining precision.
142
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
243
use scale_info::TypeInfo;
344
use sp_arithmetic::ArithmeticError;
@@ -6,20 +47,50 @@ use substrate_fixed::traits::{FixedSigned, FixedUnsigned};
647
use super::{calculate_accumulated_passive_issuance, square, BondingFunction};
748
use crate::PassiveSupply;
849

50+
/// A struct representing the unchecked input parameters for a polynomial bonding curve.
51+
/// This struct is used to convert the input parameters to the correct fixed-point type.
52+
///
53+
/// The input struct assumes that the coefficients are precomputed according to the integral rules of the polynomial function.
54+
///
55+
/// ### Example
56+
///
57+
/// For a polynomial cost function `c(s) = 3 * s^2 + 2 * s + 2`
58+
///
59+
/// which is resulting into the antiderivative `C(s) = (3 / 3) * s^3 + (2 / 2) * s^2 + 2 * s`
60+
/// the input parameters would be:
61+
/// ```rust, ignore
62+
/// PolynomialParametersInput {
63+
/// m: 1,
64+
/// n: 1,
65+
/// o: 2,
66+
/// }
67+
/// ```
968
#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
1069
pub struct PolynomialParametersInput<Parameter> {
70+
/// Coefficient for the cubic part.
1171
pub m: Parameter,
72+
/// Coefficient for the quadratic part.
1273
pub n: Parameter,
74+
/// Coefficient for the linear part.
1375
pub o: Parameter,
1476
}
1577

78+
/// A struct representing the validated parameters for a polynomial bonding curve.
79+
/// This struct is used to store the parameters for a polynomial bonding
80+
/// curve and to perform calculations using the polynomial bonding curve.
1681
#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
1782
pub struct PolynomialParameters<Parameter> {
83+
/// Coefficient for the cubic part.
1884
pub m: Parameter,
85+
/// Coefficient for the quadratic part.
1986
pub n: Parameter,
87+
/// Coefficient for the linear part.
2088
pub o: Parameter,
2189
}
2290

91+
/// Implementation of the TryFrom trait for `PolynomialParametersInput` to convert the input parameters to
92+
/// the correct fixed-point type. The TryFrom implementation for `PolynomialParameters` will fail if the
93+
/// conversion to the fixed-point type fails.
2394
impl<I: FixedUnsigned, C: FixedSigned> TryFrom<PolynomialParametersInput<I>> for PolynomialParameters<C> {
2495
type Error = ();
2596
fn try_from(value: PolynomialParametersInput<I>) -> Result<Self, Self::Error> {
@@ -35,6 +106,7 @@ impl<Parameter> BondingFunction<Parameter> for PolynomialParameters<Parameter>
35106
where
36107
Parameter: FixedSigned,
37108
{
109+
/// Calculate the cost of purchasing/selling assets using the polynomial bonding curve.
38110
fn calculate_costs(
39111
&self,
40112
low: Parameter,

pallets/pallet-bonded-coins/src/curves/square_root.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,38 @@
1+
/// Square Root Bonding Curve Implementation.
2+
///
3+
/// This module provides an implementation of a square root bonding curve, with the integral precomputed for efficiency.
4+
///
5+
/// ### Cost Function
6+
/// The cost function is defined as:
7+
/// ```text
8+
/// c(s) = m * sqrt(s) + n
9+
/// ```
10+
/// This function, `c(s)`, determines the price for purchasing or selling assets at any supply point `s`.
11+
/// The total transaction cost is calculated as the integral of `c(s)` between the start point and `s`.
12+
///
13+
/// ### Antiderivative
14+
/// The indefinite integral of the cost function is:
15+
/// ```text
16+
/// C(s) = (2/3) * m * s^(3/2) + n * s
17+
/// ```
18+
/// Where:
19+
/// - `s` is the supply of assets,
20+
/// - `m` is the coefficient for the square root term,
21+
/// - `n` is the coefficient for the linear term.
22+
///
23+
/// `C(s)` represents the total cost of purchasing or selling assets up to the current supply `s`.
24+
/// To calculate the incremental cost of a transaction, use the formula:
25+
/// ```text
26+
/// Incremental Cost = C(s) - C(s*)
27+
/// ```
28+
/// Here, `s*` represents the initial supply before the transaction, and `s` is the supply after the transaction.
29+
///
30+
/// ### Optimization for Numerical Stability
31+
/// Calculating `s^(3/2)` directly can lead to overflow in fixed-point arithmetic. To mitigate this, the calculation is factored as:
32+
/// ```text
33+
/// sqrt(s^3) = sqrt(s) * s
34+
/// ```
35+
/// By expressing `s^(3/2)` as the product of `sqrt(s)` and `s`, we reduce the risk of overflow while maintaining computational precision.
136
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
237
use scale_info::TypeInfo;
338
use sp_arithmetic::ArithmeticError;
@@ -9,18 +44,41 @@ use substrate_fixed::{
944
use super::{calculate_accumulated_passive_issuance, BondingFunction};
1045
use crate::{PassiveSupply, Precision};
1146

47+
/// A struct representing the unchecked input parameters for a square root bonding curve.
48+
/// This struct is used to convert the input parameters to the correct fixed-point type.
49+
///
50+
/// The input struct assumes that the coefficients are precomputed according to the integral rules of the square root function./// ### Example
51+
///
52+
/// For a square root cost function `c(s) = 3 * s^1/2 + 2
53+
///
54+
/// which is resulting into the antiderivative `C(s) = (6 / 3) * s^(1/2) + 2 * s`
55+
/// the input parameters would be:
56+
/// ```rust, ignore
57+
/// SquareRootParametersInput {
58+
/// m: 2,
59+
/// n: 2,
60+
/// }
61+
/// ```
1262
#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
1363
pub struct SquareRootParametersInput<Parameter> {
64+
/// Coefficient for the square root part.
1465
pub m: Parameter,
66+
/// Coefficient for the linear part.
1567
pub n: Parameter,
1668
}
1769

70+
/// A struct representing the validated parameters for a square root bonding curve.
71+
/// This struct is used to store the parameters for a square root bonding curve and to perform calculations using the square root bonding curve.
1872
#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
1973
pub struct SquareRootParameters<Parameter> {
74+
/// Coefficient for the square root part.
2075
pub m: Parameter,
76+
/// Coefficient for the linear part.
2177
pub n: Parameter,
2278
}
2379

80+
/// Implementation of the TryFrom trait for `SquareRootParametersInput` to convert the input parameters to the correct fixed-point type.
81+
/// The TryFrom implementation for `SquareRootParameters` will fail if the conversion to the fixed-point type fails.
2482
impl<I: FixedUnsigned, C: FixedSigned> TryFrom<SquareRootParametersInput<I>> for SquareRootParameters<C> {
2583
type Error = ();
2684
fn try_from(value: SquareRootParametersInput<I>) -> Result<Self, Self::Error> {
@@ -35,6 +93,7 @@ impl<Parameter> BondingFunction<Parameter> for SquareRootParameters<Parameter>
3593
where
3694
Parameter: FixedSigned + PartialOrd<Precision> + From<Precision> + ToFixed,
3795
{
96+
/// Calculate the cost of purchasing/selling assets using the square root bonding curve.
3897
fn calculate_costs(
3998
&self,
4099
low: Parameter,

0 commit comments

Comments
 (0)