Skip to content

Commit

Permalink
Merge pull request #5076 from ignazio-bovo/nara-fixes-for-amm
Browse files Browse the repository at this point in the history
Nara fixes for amm
  • Loading branch information
kdembler authored Feb 22, 2024
2 parents a6e39cb + 5a0fdf7 commit 1c6b7f8
Show file tree
Hide file tree
Showing 13 changed files with 317 additions and 148 deletions.
24 changes: 23 additions & 1 deletion Cargo.lock

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

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.

29 changes: 18 additions & 11 deletions runtime-modules/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,24 @@ edition = '2018'

[dependencies]
serde = { version = "1.0.101", optional = true, features = ["derive"] }
strum = {version = "0.19", optional = true}
strum_macros = {version = "0.19", optional = true}
codec = { package = 'parity-scale-codec', version = '3.1.2', default-features = false, features = ['derive'] }
scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
sp-runtime = { package = 'sp-runtime', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'}
frame-support = { package = 'frame-support', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'}
frame-system = { package = 'frame-system', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'}
pallet-timestamp = { package = 'pallet-timestamp', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'}
sp-arithmetic = { package = 'sp-arithmetic', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'}
balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'}
sp-std = { package = 'sp-std', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9'}
strum = { version = "0.19", optional = true }
strum_macros = { version = "0.19", optional = true }
codec = { package = 'parity-scale-codec', version = '3.1.2', default-features = false, features = [
'derive',
] }
scale-info = { version = "2.1.1", default-features = false, features = [
"derive",
] }
sp-runtime = { package = 'sp-runtime', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9' }
frame-support = { package = 'frame-support', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9' }
frame-system = { package = 'frame-system', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9' }
pallet-timestamp = { package = 'pallet-timestamp', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9' }
sp-arithmetic = { package = 'sp-arithmetic', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9' }
balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9' }
sp-std = { package = 'sp-std', default-features = false, git = 'https://github.com/joystream/substrate.git', rev = '1d0eefca86ef31b9e7727df01a6ed23ad65491e9' }

[dev-dependencies]
parameterized = { version = "1.1.0" }

[features]
default = ['std']
Expand Down
66 changes: 66 additions & 0 deletions 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 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,77 @@ 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)
pub fn amm_eval_inner<
Number: CheckedAdd + CheckedSub + CheckedMul + CheckedNeg + AtLeast32BitUnsigned + Copy,
>(
x: Number,
y: Number,
a: Number,
b: Number,
) -> Option<Number> {
if x == y {
return Some(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);

first_term
.and_then(|first_term_| {
second_term.map(|second_term_| first_term_.checked_add(&second_term_))
})
.flatten()
}

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

use super::*;

#[parameterized(
input = {
(5u128, 10u128, 2u128, 4u128), // x < y
(10u128, 5u128, 2u128, 4u128), // x > y
(10u128, 10u128, 2u128, 4u128), // x = y
(u128::MAX - 1, u128::MAX , 2u128, 4u128), // overflow
(u128::MAX, u128::MAX , 2u128, 4u128), // x = y = u128::MAX
(10u128, 10u128, 0u128, 0u128), // a = b = 0
(10u128, 5u128, u128::MAX, u128::MAX), // overflow
(10u128, 10u128, u128::MAX, u128::MAX), // zero
(10u128, 5u128, 5u128, 2u128), // a = odd
},
expected = {
Some(95),
Some(95),
Some(0),
None,
Some(0),
Some(0),
None,
Some(0),
Some(160)
}
)]
fn amm_eval_inner_base_test(input: (u128, u128, u128, u128), expected: Option<u128>) {
let (x, y, a, b) = input;

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
18 changes: 13 additions & 5 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,9 +894,12 @@ 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)?;

// burn tx_fee * price
let _ = burn_from_usable::<T>(&amm_treasury_account, buy_tx_fee);

Self::deposit_event(RawEvent::TokensBoughtOnAmm(token_id, member_id, amount, buy_price));

Ok(())
Expand Down Expand Up @@ -949,9 +953,9 @@ 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)?;

// == MUTATION SAFE ==
Expand All @@ -965,8 +969,12 @@ 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)?;

// 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, sell_price));

Ok(())
Expand Down
Loading

0 comments on commit 1c6b7f8

Please sign in to comment.