Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: stableswap v2 - drift peg support #1026

Draft
wants to merge 37 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
502fd59
stableswap - creating pool with pegs
enthusiastmartin Jan 22, 2025
69643c9
prepare stableswap math to accept peg
enthusiastmartin Jan 22, 2025
9438729
set multiplier for math api
enthusiastmartin Jan 28, 2025
c9371f5
get multipliers from storage
enthusiastmartin Jan 28, 2025
c527edb
apply multipliers when calculating D and Y
enthusiastmartin Jan 28, 2025
8b1fc76
Merge branch 'master' into feat/fancy-stableswap
enthusiastmartin Feb 10, 2025
4bf6730
rename peg -> multiplier
enthusiastmartin Feb 10, 2025
9f7e76b
better naming
enthusiastmartin Feb 10, 2025
f7a1e5c
add raw oracle retrieval support
enthusiastmartin Feb 11, 2025
9431cda
add source and oracle support
enthusiastmartin Feb 11, 2025
ad3908b
plumbing
enthusiastmartin Feb 11, 2025
f5b5ef3
enble ensure_ methods in tests
enthusiastmartin Feb 11, 2025
b3f3d77
better naming and dont update when only retrieval
enthusiastmartin Feb 11, 2025
1dfcaf9
Require transactional
enthusiastmartin Feb 11, 2025
70825b2
target multipliers
enthusiastmartin Feb 11, 2025
f7186bf
add max peg update
enthusiastmartin Feb 11, 2025
dc29e2c
different source for each peg targer
enthusiastmartin Feb 12, 2025
0537a54
determine swap or liquidity operation
enthusiastmartin Feb 12, 2025
aa19700
new pegs calc update
enthusiastmartin Feb 12, 2025
34d3d4b
use correct block diff
enthusiastmartin Feb 12, 2025
d27e802
update comment
enthusiastmartin Feb 12, 2025
3bfe022
impl ratio ops
enthusiastmartin Feb 12, 2025
71f5a72
tests for peg one
enthusiastmartin Feb 12, 2025
54eaf2e
fix peg calc
enthusiastmartin Feb 12, 2025
ac2097a
add tests with fixed pegs and fees
enthusiastmartin Feb 12, 2025
1b820a2
get target pegs as initial pegs in on create pool
enthusiastmartin Feb 13, 2025
a69eaf5
recalculate trade fee with pegs
enthusiastmartin Feb 13, 2025
b1a72d7
repeg in calculate_y
enthusiastmartin Feb 13, 2025
f3ab1bd
better naming
enthusiastmartin Feb 13, 2025
2655aeb
fix share price calcualtion
enthusiastmartin Feb 14, 2025
909189d
remove test function
enthusiastmartin Feb 14, 2025
f8061c1
fix spot price calculation
enthusiastmartin Feb 14, 2025
01173de
Merge branch 'master' into feat/fancy-stableswap
enthusiastmartin Feb 14, 2025
7e1bc55
dont allow diffent decimlas
enthusiastmartin Feb 14, 2025
47eebbb
refactor math operation
enthusiastmartin Feb 14, 2025
09540fc
happy clippy happy life
enthusiastmartin Feb 14, 2025
1022856
simplfy
enthusiastmartin Feb 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

236 changes: 235 additions & 1 deletion math/src/ratio.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use crate::support::rational::{round_to_rational, Rounding};
use crate::to_u128_wrapper;
use codec::{Decode, Encode, MaxEncodedLen};
use core::cmp::{Ord, Ordering, PartialOrd};
use num_traits::Zero;
use num_traits::{SaturatingAdd, SaturatingMul, SaturatingSub, Zero};
use primitive_types::U128;
use scale_info::TypeInfo;
use serde::{Deserialize, Serialize};
use sp_arithmetic::helpers_128bit;
use sp_std::ops::{Add, Mul, Sub};

/// A rational number represented by a `n`umerator and `d`enominator.
#[derive(Clone, Copy, Default, PartialEq, Eq, Encode, Decode, Serialize, Deserialize, TypeInfo, MaxEncodedLen)]
Expand Down Expand Up @@ -115,6 +119,103 @@ impl Ord for Ratio {
}
}

impl Add for Ratio {
type Output = Self;

fn add(self, rhs: Self) -> Self::Output {
if self.n.is_zero() {
return rhs;
} else if rhs.n.is_zero() {
return self;
}
let (l_n, l_d, r_n, r_d) = to_u128_wrapper!(self.n, self.d, rhs.n, rhs.d);
let common_d = l_d.full_mul(r_d);
let l_n_common = l_n.full_mul(r_d);
let r_n_common = r_n.full_mul(l_d);
let n = l_n_common.add(r_n_common);
let d = common_d;
round_to_rational((n, d), Rounding::Nearest).into()
}
}

impl SaturatingAdd for Ratio {
fn saturating_add(&self, rhs: &Self) -> Self {
if self.n.is_zero() {
return *rhs;
} else if rhs.n.is_zero() {
return *self;
}
let (l_n, l_d, r_n, r_d) = to_u128_wrapper!(self.n, self.d, rhs.n, rhs.d);
let common_d = l_d.full_mul(r_d);
let l_n_common = l_n.full_mul(r_d);
let r_n_common = r_n.full_mul(l_d);
let n = l_n_common.saturating_add(r_n_common);
let d = common_d;
round_to_rational((n, d), Rounding::Down).into()
}
}

impl Sub for Ratio {
type Output = Self;

fn sub(self, rhs: Self) -> Self::Output {
if self.n.is_zero() || rhs.n.is_zero() {
return (self.n, self.d).into();
}
let (l_n, l_d, r_n, r_d) = to_u128_wrapper!(self.n, self.d, rhs.n, rhs.d);
// n = l.n * r.d - r.n * l.d
let n = l_n.full_mul(r_d).sub(r_n.full_mul(l_d));
// d = l.d * r.d
let d = l_d.full_mul(r_d);
round_to_rational((n, d), Rounding::Nearest).into()
}
}

impl SaturatingSub for Ratio {
fn saturating_sub(&self, rhs: &Self) -> Self {
if self.n.is_zero() || rhs.n.is_zero() {
return (self.n, self.d).into();
}
let (l_n, l_d, r_n, r_d) = to_u128_wrapper!(self.n, self.d, rhs.n, rhs.d);
// n = l.n * r.d - r.n * l.d
let n = l_n.full_mul(r_d).saturating_sub(r_n.full_mul(l_d));
// d = l.d * r.d
let d = l_d.full_mul(r_d);
round_to_rational((n, d), Rounding::Nearest).into()
}
}

impl Mul for Ratio {
type Output = Self;

fn mul(self, rhs: Self) -> Self::Output {
if self.is_zero() || rhs.is_zero() {
return Self::zero();
}
let (l_n, l_d, r_n, r_d) = to_u128_wrapper!(self.n, self.d, rhs.n, rhs.d);
let n = l_n.full_mul(r_n);
let d = l_d.full_mul(r_d);
round_to_rational((n, d), Rounding::Nearest).into()
}
}

impl SaturatingMul for Ratio {
fn saturating_mul(&self, rhs: &Self) -> Self {
self.mul(*rhs)
}
}

impl Ratio {
pub fn saturating_div(&self, rhs: &Self) -> Self {
if rhs.is_zero() {
return Self::zero(); // Handle division by zero
}
let (l_n, l_d, r_n, r_d) = to_u128_wrapper!(self.n, self.d, rhs.n, rhs.d);
let n = l_n.full_mul(r_d);
let d = l_d.full_mul(r_n);
round_to_rational((n, d), Rounding::Nearest).into()
}
}
#[cfg(feature = "std")]
impl sp_std::fmt::Debug for Ratio {
fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result {
Expand All @@ -134,3 +235,136 @@ impl sp_std::fmt::Debug for Ratio {
write!(f, "Ratio({} / {})", self.n, self.d)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_add_ratios() {
let ratio1 = Ratio::new(1, 2);
let ratio2 = Ratio::new(1, 3);
let result = ratio1 + ratio2;
assert_eq!(result, Ratio::new(5, 6));
}

#[test]
fn test_sub_ratios() {
let ratio1 = Ratio::new(2, 1);
let ratio2 = Ratio::new(1, 2);
let result = ratio1 - ratio2;
assert_eq!(result, Ratio::new(3, 2));
}

#[test]
fn test_add_zero_ratio() {
let ratio1 = Ratio::new(1, 2);
let zero_ratio = Ratio::zero();
let result = ratio1 + zero_ratio;
assert_eq!(result, ratio1);
}

#[test]
fn test_sub_zero_ratio() {
let ratio1 = Ratio::new(1, 2);
let zero_ratio = Ratio::zero();
let result = ratio1 - zero_ratio;
assert_eq!(result, ratio1);
}

#[test]
fn test_add_one_ratio() {
let ratio1 = Ratio::new(1, 2);
let one_ratio = Ratio::one();
let result = ratio1 + one_ratio;
assert_eq!(result, Ratio::new(3, 2));
}

#[test]
fn test_sub_one_ratio() {
let ratio1 = Ratio::new(3, 2);
let one_ratio = Ratio::one();
let result = ratio1 - one_ratio;
assert_eq!(result, Ratio::new(1, 2));
}

#[test]
fn test_add_large_ratios() {
let ratio1 = Ratio::new(u128::MAX, 111111111111);
let ratio2 = Ratio::new(u128::MAX, 444444444444);
let result = ratio1 + ratio2;
assert_eq!(result, Ratio::new(171936116567241990952755394961819566079, 44913318605));
}

#[test]
fn test_sub_large() {
let ratio1 = Ratio::new(u128::MAX, 2);
let ratio2 = Ratio::new(u128::MAX, 3);
let result = ratio1 - ratio2;
assert_eq!(result, Ratio::new(340282366920938463463374607431768211455, 6));
}

#[test]
fn test_sub_large_ratios() {
let ratio1 = Ratio::new(u128::MAX, 1);
let ratio2 = Ratio::new(u128::MAX / 2, 1);
let result = ratio1 - ratio2;
assert_eq!(result, Ratio::new(u128::MAX / 2 + 1, 1));
}

#[test]
fn test_add_small_ratios() {
let ratio1 = Ratio::new(1, u128::MAX);
let ratio2 = Ratio::new(1, u128::MAX);
let result = ratio1 + ratio2;
assert_eq!(result, Ratio::new(1, u128::MAX - 1));
}

#[test]
fn test_sub_small_ratios() {
let ratio1 = Ratio::new(1, u128::MAX);
let ratio2 = Ratio::new(1, u128::MAX);
let result = ratio1 - ratio2;
assert!(result.is_zero());
}

#[test]
fn test_mul_ratios() {
let ratio1 = Ratio::new(1, 2);
let ratio2 = Ratio::new(2, 3);
let result = ratio1 * ratio2;
assert_eq!(result, Ratio::new(2, 6));
}

#[test]
fn test_mul_zero_ratio() {
let ratio1 = Ratio::new(1, 2);
let zero_ratio = Ratio::zero();
let result = ratio1 * zero_ratio;
assert_eq!(result, Ratio::zero());
}

#[test]
fn test_mul_one_ratio() {
let ratio1 = Ratio::new(1, 2);
let one_ratio = Ratio::one();
let result = ratio1 * one_ratio;
assert_eq!(result, ratio1);
}

#[test]
fn test_mul_large_ratios() {
let ratio1 = Ratio::new(u128::MAX, 2);
let ratio2 = Ratio::new(2, 3);
let result = ratio1 * ratio2;
assert_eq!(result, Ratio::new(u128::MAX, 3));
}

#[test]
fn test_mul_small_ratios() {
let ratio1 = Ratio::new(1, u128::MAX);
let ratio2 = Ratio::new(1, u128::MAX);
let result = ratio1 * ratio2;
assert_eq!(result, Ratio::new(1, u128::MAX - 1));
}
}
Loading
Loading