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

Nara fixes for amm #5076

Merged
merged 8 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
2 changes: 1 addition & 1 deletion chain-metadata.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion query-node/chain-metadata/2002.json

Large diffs are not rendered by default.

98 changes: 97 additions & 1 deletion runtime-modules/common/src/numerical.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use core::ops::Div;
use core::{fmt::Debug, ops::Div};

use sp_arithmetic::traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedMul, CheckedNeg, CheckedSub};
use sp_runtime::{
traits::{One, Saturating},
FixedPointNumber, FixedU128, PerThing, Permill, Perquintill,
Expand Down Expand Up @@ -87,12 +88,107 @@ pub fn one_plus_interest_pow_fixed(interest: Permill, exp: FixedU128) -> FixedU1
base_pow_int.mul(base_pow_frac)
}

// computes integral of integral at + b dt from x to y = a (y^2/2 - x^2/2) + b (y - x)
#[derive(Debug, PartialEq)]
pub enum SignedResult<Number> {
Positive(Number),
Negative(Number),
}
pub fn amm_eval_inner<
Number: CheckedAdd + CheckedSub + CheckedMul + CheckedNeg + AtLeast32BitUnsigned + Copy,
>(
x: Number,
y: Number,
a: Number,
b: Number,
) -> Option<SignedResult<Number>> {
if x == y {
return Some(SignedResult::Positive(Number::zero()));
}
let lower_bound = y.min(x);
let upper_bound = y.max(x);
let upper_bound_sq = upper_bound.checked_mul(&upper_bound);
let lower_bound_sq = lower_bound.checked_mul(&lower_bound);
let first_term_coeff = a.div(2u32.into());

// squared diff between two Option<Number>: upper_bound_sq - lower_bound_sq
let diff_sq = upper_bound_sq.and_then(|upper_| lower_bound_sq.map(|lower_| upper_.sub(lower_)));
let diff = upper_bound.sub(lower_bound);
let first_term = diff_sq.and_then(|diff_sq| diff_sq.checked_mul(&first_term_coeff));
let second_term = diff.checked_mul(&b);

// diff
let res = first_term
.and_then(|first_term_| {
second_term.map(|second_term_| first_term_.checked_add(&second_term_))
})
.flatten();

if lower_bound == x {
res.map(|res_| SignedResult::Positive(res_))
} else {
res.map(|res_| SignedResult::Negative(res_))
}
}

#[cfg(test)]
mod numerical_tests {
use sp_runtime::traits::Zero;

use super::*;

#[test]
fn amm_eval_inner_returns_positive_zero_when_x_equals_y() {
let x = 10u32;
let y = 10u32;
let a = 2u32;
let b = 4u32;
let expected = Some(SignedResult::Positive(0));

let result = amm_eval_inner(x, y, a, b);

assert_eq!(result, expected);
}

#[test]
fn amm_eval_inner_returns_positive_result_for_normal_case() {
let x = 5u32;
let y = 10u32;
let a = 2u32;
let b = 4u32;
let expected = Some(SignedResult::Positive(95));

let result = amm_eval_inner(x, y, a, b);

assert_eq!(result, expected);
}

#[test]
fn amm_eval_inner_returns_negative_result_for_normal_case() {
let x = 10u32;
let y = 5u32;
let a = 2u32;
let b = 4u32;
let expected = Some(SignedResult::Negative(95));

let result = amm_eval_inner(x, y, a, b);

assert_eq!(result, expected);
}

#[test]
fn amm_eval_inner_handles_overflow() {
let x = u32::MAX;
let y = u32::MAX - 1;
let a = 2u32;
let b = 4u32;
let expected = None;

let result = amm_eval_inner(x, y, a, b);

assert_eq!(result, expected);
}

#[test]
fn log_approximation_is_accurate_up_to_14_dec_places() {
let expected = Perquintill::from_float(0.139761942375158f64); // https://www.wolframalpha.com/input?i=ln%281+%2B+0.15%29
Expand Down
3 changes: 3 additions & 0 deletions runtime-modules/project-token/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ decl_error! {
/// Curve slope parameters below minimum allowed
CurveSlopeParametersTooLow,

/// Attempting to sell more than amm provided supply
NotEnoughTokenMintedByAmmForThisSale,

/// -------- Patronage --------------------------------------------------

/// Target Rate is higher than current patronage rate
Expand Down
21 changes: 15 additions & 6 deletions runtime-modules/project-token/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use scale_info::TypeInfo;
use sp_arithmetic::traits::{AtLeast32BitUnsigned, One, Saturating, Zero};
use sp_runtime::{
traits::{AccountIdConversion, CheckedAdd},
PerThing, Permill,
Permill,
};
use sp_std::collections::btree_map::BTreeMap;
use sp_std::convert::TryInto;
Expand Down Expand Up @@ -856,7 +856,8 @@ decl_module! {
let amm_treasury_account = Self::amm_treasury_account(token_id);
let price = curve.eval::<T>(amount, AmmOperation::Buy)?.into();
let bloat_bond = Self::bloat_bond();
let buy_price = Self::amm_buy_tx_fees().mul_floor(price).checked_add(&price).ok_or(Error::<T>::ArithmeticError)?;
let buy_tx_fee = Self::amm_buy_tx_fees().mul_floor(price);
let buy_price = buy_tx_fee.checked_add(&price).ok_or(Error::<T>::ArithmeticError)?;

let joys_required = if !user_account_data_exists {
buy_price.saturating_add(bloat_bond)
Expand Down Expand Up @@ -893,10 +894,13 @@ decl_module! {
token_data.increase_amm_bought_amount_by(amount);
});

// TODO: redirect tx fees revenue to council
// transfer tx_fee * price + price
Self::transfer_joy(&sender, &amm_treasury_account, buy_price)?;

Self::deposit_event(RawEvent::TokensBoughtOnAmm(token_id, member_id, amount, buy_price));
// burn tx_fee * price
let _ = burn_from_usable::<T>(&amm_treasury_account, buy_tx_fee);
kdembler marked this conversation as resolved.
Show resolved Hide resolved

Self::deposit_event(RawEvent::TokensBoughtOnAmm(token_id, member_id, amount, price));
kdembler marked this conversation as resolved.
Show resolved Hide resolved

Ok(())
}
Expand Down Expand Up @@ -949,7 +953,8 @@ decl_module! {
ensure!(desired_price.saturating_sub(price) <= slippage_tolerance.mul_floor(desired_price), Error::<T>::SlippageToleranceExceeded);
}

let sell_price = Self::amm_sell_tx_fees().left_from_one().mul_floor(price);
let sell_tx_fee = Self::amm_sell_tx_fees().mul_floor(price);
let sell_price = price.saturating_sub(sell_tx_fee);

// TODO: redirect tx fees revenue to council
Self::ensure_can_transfer_joy(&amm_treasury_account, sell_price)?;
Expand All @@ -965,9 +970,13 @@ decl_module! {
token_data.decrease_amm_bought_amount_by(amount);
});

// transfer the price - tx_fee * price
Self::transfer_joy(&amm_treasury_account, &sender, sell_price)?;

Self::deposit_event(RawEvent::TokensSoldOnAmm(token_id, member_id, amount, sell_price));
// burn tx_fee * price
let _ = burn_from_usable::<T>(&amm_treasury_account, sell_tx_fee);

Self::deposit_event(RawEvent::TokensSoldOnAmm(token_id, member_id, amount, price));

Ok(())
}
Expand Down
Loading
Loading