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

Mdjakovic/update curve #767

Merged
merged 6 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed wrong return attribute for SubDir Query [(#756)](https://github.com/andromedaprotocol/andromeda-core/pull/756)
- fix: Prevent bypassing splitter lock via config [(#757)](https://github.com/andromedaprotocol/andromeda-core/pull/757)
- Fixed Curve ADO to be able to update curve config after reset [(#762)](https://github.com/andromedaprotocol/andromeda-core/pull/762)
- Fixed Curve ADO's query error caused by Float data type [(#767)](https://github.com/andromedaprotocol/andromeda-core/pull/767)

## Release 3

Expand Down
58 changes: 45 additions & 13 deletions contracts/math/andromeda-curve/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ use andromeda_std::{
};

use cosmwasm_std::{
entry_point, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdError, Storage,
entry_point, Binary, Decimal, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdError,
Storage,
};

use cw_utils::nonpayable;
Expand Down Expand Up @@ -170,7 +171,7 @@ pub fn query_curve_config(storage: &dyn Storage) -> Result<GetCurveConfigRespons

pub fn query_plot_y_from_x(
storage: &dyn Storage,
x_value: f64,
x_value: u64,
mdjakovic0920 marked this conversation as resolved.
Show resolved Hide resolved
) -> Result<GetPlotYFromXResponse, ContractError> {
let curve_config = CURVE_CONFIG.load(storage)?;

Expand All @@ -181,18 +182,49 @@ pub fn query_plot_y_from_x(
multiple_variable_value,
constant_value,
} => {
let curve_id_f64 = match curve_type {
CurveType::Growth => 1_f64,
CurveType::Decay => -1_f64,
let base_value_decimal = Decimal::percent(base_value * 100);
let constant_value_decimal =
Decimal::percent(constant_value.unwrap_or(DEFAULT_CONSTANT_VALUE) * 100);
let multiple_variable_value_decimal = Decimal::percent(
multiple_variable_value.unwrap_or(DEFAULT_MULTIPLE_VARIABLE_VALUE) * 100,
);

let exponent_value = multiple_variable_value_decimal
.checked_mul(Decimal::from_atomics(x_value, 18).map_err(|e| {
ContractError::CustomError {
msg: format!("Failed to create decimal for the exponent_value: {:?}", e),
}
})?)
.map_err(|_| ContractError::Overflow {})?
.atomics();

let exponent_u32 = if exponent_value.u128() > u128::from(u32::MAX) {
return Err(ContractError::CustomError {
msg: "Exponent value exceeds u32::MAX.".to_string(),
});
} else {
u32::try_from(exponent_value.u128()).map_err(|_| ContractError::CustomError {
msg: "Failed to convert exponent to u32.".to_string(),
})?
};
let base_value_f64 = base_value as f64;
let constant_value_f64 = constant_value.unwrap_or(DEFAULT_CONSTANT_VALUE) as f64;
let multiple_variable_value_f64 =
multiple_variable_value.unwrap_or(DEFAULT_MULTIPLE_VARIABLE_VALUE) as f64;

(constant_value_f64
* base_value_f64.powf(curve_id_f64 * multiple_variable_value_f64 * x_value))
.to_string()

// The argument of the checked_pow() must be u32, can not be other types
let res = constant_value_decimal
.checked_mul(
base_value_decimal
.checked_pow(exponent_u32)
.map_err(|_| ContractError::Overflow {})?,
)
.map_err(|_| ContractError::Overflow {})?;

let res_by_curve_type = match curve_type {
CurveType::Growth => res,
CurveType::Decay => Decimal::one()
.checked_div(res)
.map_err(|_| ContractError::Underflow {})?,
};

res_by_curve_type.to_string()
}
};

Expand Down
2 changes: 1 addition & 1 deletion contracts/math/andromeda-curve/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ impl MockCurve {
res
}

pub fn query_plot_y_from_x(&self, app: &mut MockApp, x_value: f64) -> GetPlotYFromXResponse {
pub fn query_plot_y_from_x(&self, app: &mut MockApp, x_value: u64) -> GetPlotYFromXResponse {
let msg = QueryMsg::GetPlotYFromX { x_value };
let res: GetPlotYFromXResponse = self.query(app, msg);
res
Expand Down
2 changes: 1 addition & 1 deletion contracts/math/andromeda-curve/src/testing/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ pub fn query_curve_config(deps: Deps) -> Result<GetCurveConfigResponse, Contract

pub fn query_plot_y_from_x(
deps: Deps,
x_value: f64,
x_value: u64,
) -> Result<GetPlotYFromXResponse, ContractError> {
let res = query(deps, mock_env(), QueryMsg::GetPlotYFromX { x_value });
match res {
Expand Down
48 changes: 33 additions & 15 deletions contracts/math/andromeda-curve/src/testing/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@ fn test_query_curve_config_base_is_0() {
);
}

#[test_case(2_f64, "4".to_string() ; "exp(2, 2)")]
#[test_case(3_f64, "8".to_string() ; "exp(2, 3)")]
#[test_case(4_f64, "16".to_string() ; "exp(2, 4)")]
fn test_query_plot_y_from_x_base_2_growth(input_x: f64, expected_y: String) {
#[test_case(2, "4".to_string() ; "exp(2, 2)")]
#[test_case(3, "8".to_string() ; "exp(2, 3)")]
#[test_case(4, "16".to_string() ; "exp(2, 4)")]
fn test_query_plot_y_from_x_base_2_growth(input_x: u64, expected_y: String) {
let (deps, _info) = proper_initialization(
CurveConfig::ExpConfig {
curve_type: CurveType::Growth,
Expand All @@ -169,13 +169,13 @@ fn test_query_plot_y_from_x_base_2_growth(input_x: f64, expected_y: String) {
);

let res = query_plot_y_from_x(deps.as_ref(), input_x).unwrap().y_value;
assert_eq!(res, expected_y);
assert_eq!(res.to_string(), expected_y);
}

#[test_case(2_f64, "9".to_string() ; "exp(3, 2)")]
#[test_case(3_f64, "27".to_string() ; "exp(3, 3)")]
#[test_case(4_f64, "81".to_string() ; "exp(3, 4)")]
fn test_query_plot_y_from_x_base_3_growth(input_x: f64, expected_y: String) {
#[test_case(2, "9".to_string() ; "exp(3, 2)")]
#[test_case(3, "27".to_string() ; "exp(3, 3)")]
#[test_case(4, "81".to_string() ; "exp(3, 4)")]
fn test_query_plot_y_from_x_base_3_growth(input_x: u64, expected_y: String) {
let (deps, _info) = proper_initialization(
CurveConfig::ExpConfig {
curve_type: CurveType::Growth,
Expand All @@ -187,13 +187,31 @@ fn test_query_plot_y_from_x_base_3_growth(input_x: f64, expected_y: String) {
);

let res = query_plot_y_from_x(deps.as_ref(), input_x).unwrap().y_value;
assert_eq!(res, expected_y);
assert_eq!(res.to_string(), expected_y);
}

#[test_case(2_f64, "0.25".to_string() ; "exp(1/2, 2)")]
#[test_case(3_f64, "0.125".to_string() ; "exp(1/2, 3)")]
#[test_case(4_f64, "0.0625".to_string() ; "exp(1/2, 4)")]
fn test_query_plot_y_from_x_base_2_decay(input_x: f64, expected_y: String) {
#[test_case(2, "32".to_string() ; "exp(4, 2)")]
#[test_case(3, "128".to_string() ; "exp(4, 3)")]
#[test_case(4, "512".to_string() ; "exp(4, 4)")]
fn test_query_plot_y_from_x_base_4_growth_constant_2(input_x: u64, expected_y: String) {
let (deps, _info) = proper_initialization(
CurveConfig::ExpConfig {
curve_type: CurveType::Growth,
base_value: 4,
multiple_variable_value: None,
constant_value: Some(2),
},
None,
);

let res = query_plot_y_from_x(deps.as_ref(), input_x).unwrap().y_value;
assert_eq!(res.to_string(), expected_y);
}

#[test_case(2, "0.25".to_string() ; "exp(1/2, 2)")]
#[test_case(3, "0.125".to_string() ; "exp(1/2, 3)")]
#[test_case(4, "0.0625".to_string() ; "exp(1/2, 4)")]
fn test_query_plot_y_from_x_base_2_decay(input_x: u64, expected_y: String) {
let (deps, _info) = proper_initialization(
CurveConfig::ExpConfig {
curve_type: CurveType::Decay,
Expand All @@ -205,5 +223,5 @@ fn test_query_plot_y_from_x_base_2_decay(input_x: f64, expected_y: String) {
);

let res = query_plot_y_from_x(deps.as_ref(), input_x).unwrap().y_value;
assert_eq!(res, expected_y);
assert_eq!(res.to_string(), expected_y);
}
2 changes: 1 addition & 1 deletion packages/andromeda-math/src/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub enum QueryMsg {
#[returns(GetCurveConfigResponse)]
GetCurveConfig {},
#[returns(GetPlotYFromXResponse)]
GetPlotYFromX { x_value: f64 },
GetPlotYFromX { x_value: u64 },
mdjakovic0920 marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want to use ::cosmwasm_std::Decimal type here rather than u64

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, Decimal's checked_pow() function must have u32 type parameter.
So it can only be calculated by u32 exponent.
In this case, the usage of u64 and Decimal are the same.
But if you want to Decimal as x_value's input type, I will do that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I use the Decimal as x_value?

}

#[cw_serde]
Expand Down
Loading