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

Add PrecDec impl [NTRN-436] #6

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions packages/neutron-std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ pub mod shim;
pub mod types;

pub use shim::{cosmwasm_to_proto_coins, try_proto_to_cosmwasm_coins};

pub mod util;
65 changes: 58 additions & 7 deletions packages/neutron-std/src/serde/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use std::{
struct StringOrNumberVisitor<T> {
p: PhantomData<T>,
}
// The Visitor helps deserialize a number, both from its numerical JSON representation and from a string.
// For example, for the struct:
// The Visitor helps deserialize a number, both from its numerical JSON representation and from a string.
// For example, for the struct:
// ```rust
// struct Foo {
// pub bar: i32;
Expand Down Expand Up @@ -205,11 +205,11 @@ pub mod as_option_base64_encoded_string {
}


// NumberOrString is a helper enum that helps us determine which
// JSON numeric representation we are working with. If it's a string,
// we will get the value `NumberOrString::String("-11")`.
// If we are dealing with a numeric representation,
// we will get `NumberOrString::Number(-11i64)`.
// NumberOrString is a helper enum that helps us determine which
// JSON numeric representation we are working with. If it's a string,
// we will get the value `NumberOrString::String("-11")`.
// If we are dealing with a numeric representation,
// we will get `NumberOrString::Number(-11i64)`.
// Then, using pattern matching, we can select the appropriate algorithm to work with the data.
#[derive(Deserialize, Debug, PartialEq)]
#[serde(untagged)]
Expand All @@ -228,3 +228,54 @@ fn parse_test() {
let res = serde_json_wasm::from_str::<NumberOrString<i64>>(str).unwrap();
assert_eq!(res, NumberOrString::String("-11".to_string()));
}

pub mod as_option_prec_dec {

use crate::util::precdec::PrecDec;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};

pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<PrecDec>, D::Error>
where
D: Deserializer<'de>,
{
let encoded_prec_dec_str: Option<String> = Option::deserialize(deserializer)?;
match encoded_prec_dec_str {
Some(s) => PrecDec::from_prec_dec_str(s.as_str())
.map(|p| Some(p))
.map_err(de::Error::custom),
None => Ok(None),
}
}

pub fn serialize<S>(value: &Option<PrecDec>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match value {
Some(p) => p.serialize(serializer),

None => serializer.serialize_none(),
}
}
}

pub mod as_prec_dec {
use crate::util::precdec::PrecDec;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};

pub fn deserialize<'de, D>(deserializer: D) -> Result<PrecDec, D::Error>
where
D: Deserializer<'de>,
{
let encoded_prec_dec_str: String = String::deserialize(deserializer)?;

PrecDec::from_prec_dec_str(&encoded_prec_dec_str.to_owned()).map_err(de::Error::custom)
}

pub fn serialize<S>(value: &PrecDec, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
value.serialize(serializer)
}
}
113 changes: 94 additions & 19 deletions packages/neutron-std/src/types/neutron/dex/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,28 @@ pub struct PoolReserves {
pub reserves_maker_denom: ::prost::alloc::string::String,
/// DEPRECATED: price_taker_to_maker will be removed in future release, `maker_price` should always be used.
#[deprecated]
#[prost(string, tag = "3")]
pub price_taker_to_maker: ::prost::alloc::string::String,
#[prost(message, required, tag = "3")]
#[serde(
serialize_with = "crate::serde::as_prec_dec::serialize",
deserialize_with = "crate::serde::as_prec_dec::deserialize"
)]
pub price_taker_to_maker: crate::util::precdec::PrecDec,
/// DEPRECATED: price_opposite_taker_maker was an internal implementation detail and will be removed in a future release.
/// It is being kept strictly for backwards compatibility. The actual field value is unused.
#[deprecated]
#[prost(string, tag = "4")]
pub price_opposite_taker_to_maker: ::prost::alloc::string::String,
#[prost(message, required, tag = "4")]
#[serde(
serialize_with = "crate::serde::as_prec_dec::serialize",
deserialize_with = "crate::serde::as_prec_dec::deserialize"
)]
pub price_opposite_taker_to_maker: crate::util::precdec::PrecDec,
/// This is the price of the PoolReserves denominated in the opposite token. (ie. 1 TokenA with a maker_price of 10 is worth 10 TokenB )
#[prost(string, tag = "5")]
pub maker_price: ::prost::alloc::string::String,
#[prost(message, required, tag = "5")]
#[serde(
serialize_with = "crate::serde::as_prec_dec::serialize",
deserialize_with = "crate::serde::as_prec_dec::deserialize"
)]
pub maker_price: crate::util::precdec::PrecDec,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(
Expand Down Expand Up @@ -224,11 +236,19 @@ pub struct LimitOrderTranche {
pub expiration_time: ::core::option::Option<crate::shim::Timestamp>,
/// DEPRECATED: price_taker_to_maker will be removed in future release, `maker_price` should always be used.
#[deprecated]
#[prost(string, tag = "7")]
pub price_taker_to_maker: ::prost::alloc::string::String,
#[prost(message, required, tag = "7")]
#[serde(
serialize_with = "crate::serde::as_prec_dec::serialize",
deserialize_with = "crate::serde::as_prec_dec::deserialize"
)]
pub price_taker_to_maker: crate::util::precdec::PrecDec,
/// This is the price of the LimitOrder denominated in the opposite token. (ie. 1 TokenA with a maker_price of 10 is worth 10 TokenB )
#[prost(string, tag = "8")]
pub maker_price: ::prost::alloc::string::String,
#[prost(message, required, tag = "8")]
#[serde(
serialize_with = "crate::serde::as_prec_dec::serialize",
deserialize_with = "crate::serde::as_prec_dec::deserialize"
)]
pub maker_price: crate::util::precdec::PrecDec,
}
/// Params defines the parameters for the module.
#[allow(clippy::derive_partial_eq_without_eq)]
Expand Down Expand Up @@ -467,15 +487,23 @@ pub struct MsgPlaceLimitOrder {
#[prost(string, tag = "10")]
#[prost(optional)]
pub max_amount_out: ::core::option::Option<::prost::alloc::string::String>,
#[prost(string, tag = "11")]
#[prost(message, tag = "11")]
#[serde(
serialize_with = "crate::serde::as_option_prec_dec::serialize",
deserialize_with = "crate::serde::as_option_prec_dec::deserialize"
)]
#[prost(optional)]
pub limit_sell_price: ::core::option::Option<::prost::alloc::string::String>,
pub limit_sell_price: ::core::option::Option<crate::util::precdec::PrecDec>,
/// min_average_sell_price is an optional parameter that sets a required minimum average price for the entire trade.
/// if the min_average_sell_price is not met the trade will fail.
/// If min_average_sell_price is omitted limit_sell_price will be used instead
#[prost(string, tag = "12")]
#[prost(message, tag = "12")]
#[serde(
serialize_with = "crate::serde::as_option_prec_dec::serialize",
deserialize_with = "crate::serde::as_option_prec_dec::deserialize"
)]
#[prost(optional)]
pub min_average_sell_price: ::core::option::Option<::prost::alloc::string::String>,
pub min_average_sell_price: ::core::option::Option<crate::util::precdec::PrecDec>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(
Expand Down Expand Up @@ -618,8 +646,12 @@ pub struct MsgMultiHopSwap {
pub routes: ::prost::alloc::vec::Vec<MultiHopRoute>,
#[prost(string, tag = "4")]
pub amount_in: ::prost::alloc::string::String,
#[prost(string, tag = "5")]
pub exit_limit_price: ::prost::alloc::string::String,
#[prost(message, required, tag = "5")]
#[serde(
serialize_with = "crate::serde::as_prec_dec::serialize",
deserialize_with = "crate::serde::as_prec_dec::deserialize"
)]
pub exit_limit_price: crate::util::precdec::PrecDec,
/// If pickBestRoute == true then all routes are run and the route with the
/// best price is chosen otherwise, the first succesful route is used.
#[prost(bool, tag = "6")]
Expand Down Expand Up @@ -1425,8 +1457,12 @@ pub struct QueryEstimateMultiHopSwapRequest {
pub routes: ::prost::alloc::vec::Vec<MultiHopRoute>,
#[prost(string, tag = "4")]
pub amount_in: ::prost::alloc::string::String,
#[prost(string, tag = "5")]
pub exit_limit_price: ::prost::alloc::string::String,
#[prost(message, required, tag = "5")]
#[serde(
serialize_with = "crate::serde::as_prec_dec::serialize",
deserialize_with = "crate::serde::as_prec_dec::deserialize"
)]
pub exit_limit_price: crate::util::precdec::PrecDec,
/// If pickBestRoute == true then all routes are run and the route with the
/// best price is chosen otherwise, the first succesful route is used.
#[prost(bool, tag = "6")]
Expand Down Expand Up @@ -2036,7 +2072,7 @@ impl<'a, Q: cosmwasm_std::CustomQuery> DexQuerier<'a, Q> {
receiver: ::prost::alloc::string::String,
routes: ::prost::alloc::vec::Vec<MultiHopRoute>,
amount_in: ::prost::alloc::string::String,
exit_limit_price: ::prost::alloc::string::String,
exit_limit_price: crate::util::precdec::PrecDec,
pick_best_route: bool,
) -> Result<QueryEstimateMultiHopSwapResponse, cosmwasm_std::StdError> {
QueryEstimateMultiHopSwapRequest {
Expand Down Expand Up @@ -2141,3 +2177,42 @@ impl<'a, Q: cosmwasm_std::CustomQuery> DexQuerier<'a, Q> {
QuerySimulateMultiHopSwapRequest { msg }.query(self.querier)
}
}

#[cfg(test)]
mod tests {
use std::str::FromStr;

use prost::Message;

use crate::util::precdec::PrecDec;

use super::*;

#[test]
fn test_marshall_placelimitorder(){
let price_opt = Some(PrecDec::from_str("1.1").unwrap());
let lo = MsgPlaceLimitOrder{
creator: "test".to_string(),
receiver: "test".to_string(),
token_in: "TokenA".to_string(),
token_out: "TokenB".to_string(),
tick_index_in_to_out: 99,
amount_in: "1".to_string(),
order_type: 4,
expiration_time: None,
limit_sell_price: price_opt,
max_amount_out: None,
min_average_sell_price: None,
};
let mut prost_buf = Vec::new();
lo.encode(&mut prost_buf).unwrap();

assert_eq!(vec![10, 4, 116, 101, 115, 116, 18, 4, 116, 101, 115, 116, 26, 6, 84, 111, 107, 101, 110, 65, 34, 6, 84, 111, 107, 101, 110, 66, 40, 99, 58, 1, 49, 64, 4, 90, 28, 49, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48], prost_buf);


let decoded: MsgPlaceLimitOrder = MsgPlaceLimitOrder::decode(&prost_buf[..]).unwrap();
print!("decoded: {:?}", decoded);


}
}
8 changes: 6 additions & 2 deletions packages/neutron-std/src/types/neutron/dex/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ pub struct Params {
deserialize_with = "crate::serde::as_str_vec::deserialize"
)]
pub fee_tiers: ::prost::alloc::vec::Vec<u64>,
#[prost(string, tag = "2")]
pub max_true_taker_spread: ::prost::alloc::string::String,
#[prost(message, required, tag = "2")]
#[serde(
serialize_with = "crate::serde::as_prec_dec::serialize",
deserialize_with = "crate::serde::as_prec_dec::deserialize"
)]
pub max_true_taker_spread: crate::util::precdec::PrecDec,
}
84 changes: 84 additions & 0 deletions packages/neutron-std/src/util/forward_ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/// # ⚠ THIS IS AN INTERNAL IMPLEMENTATION DETAIL. DO NOT USE.
///
/// Given an implementation of `T == U`, implements:
/// - `&T == U`
/// - `T == &U`
///
/// We don't need to add `&T == &U` here because this is implemented automatically.
#[doc(hidden)]
#[macro_export]
macro_rules! forward_ref_partial_eq {
($t:ty, $u:ty) => {
// `&T == U`
impl<'a> PartialEq<$u> for &'a $t {
#[inline]
fn eq(&self, rhs: &$u) -> bool {
**self == *rhs // Implement via T == U
}
}

// `T == &U`
impl PartialEq<&$u> for $t {
#[inline]
fn eq(&self, rhs: &&$u) -> bool {
*self == **rhs // Implement via T == U
}
}
};
}

/// implements binary operators "&T op U", "T op &U", "&T op &U"
/// based on "T op U" where T and U are expected to be `Copy`able
///
/// Copied from `libcore`
macro_rules! forward_ref_binop {
(impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
impl<'a> $imp<$u> for &'a $t {
type Output = <$t as $imp<$u>>::Output;

#[inline]
#[track_caller]
fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
$imp::$method(*self, other)
}
}

impl $imp<&$u> for $t {
type Output = <$t as $imp<$u>>::Output;

#[inline]
#[track_caller]
fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
$imp::$method(self, *other)
}
}

impl $imp<&$u> for &$t {
type Output = <$t as $imp<$u>>::Output;

#[inline]
#[track_caller]
fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
$imp::$method(*self, *other)
}
}
};
}

/// implements "T op= &U", based on "T op= U"
/// where U is expected to be `Copy`able
///
/// Copied from `libcore`
macro_rules! forward_ref_op_assign {
(impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
impl $imp<&$u> for $t {
#[inline]
#[track_caller]
fn $method(&mut self, other: &$u) {
$imp::$method(self, *other);
}
}
};
}

pub(crate) use {forward_ref_binop, forward_ref_op_assign, forward_ref_partial_eq};
2 changes: 2 additions & 0 deletions packages/neutron-std/src/util/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod forward_ref;
pub mod precdec;
Loading