ex3-node-types 0.15.138

EX3 main node types.
Documentation
use num_bigint::BigUint;
use serde::{Deserialize, Serialize};

use crate::{impl_from_uint_for, AssetAmount, OrderId, SpotMarketId};

/// Order side
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub enum OrderSide {
    /// Ask
    /// Note: Ask means sell base asset
    Ask = 1,

    /// Bid
    /// Note: Bid means buy base asset
    Bid = 2,
}

/// Spot order detail
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct SpotOrderDetail {
    /// Order side
    pub side: OrderSide,

    /// Order price
    pub price: AssetAmount,

    /// Order volume
    /// Note: volume means base asset quantity
    pub volume: AssetAmount,
}

/// Amm V2 exact tokens
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub enum AmmV2ExactTokens {
    /// Exact input
    ExactInput {
        /// Input amount
        /// Note: input amount means the input asset quantity
        amount: AssetAmount,
        /// Min out
        /// Note: min out means the output asset quantity must be greater than or equal to the min out
        min_out: AssetAmount,
    },

    /// Exact output
    ExactOutput {
        /// Output amount
        /// Note: output amount means the output asset quantity
        amount: AssetAmount,
        /// Max in
        /// Note: max in means the input asset quantity must be less than or equal to the max in
        max_in: AssetAmount,
    },
}

/// Amm V2 order detail
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct AmmV2OrderDetail {
    /// Order side
    pub side: OrderSide,

    /// Exact tokens
    pub exact_tokens: AmmV2ExactTokens,
}

/// Order detail
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub enum SpotOrder {
    /// Spot order detail
    Spot(SpotOrderDetail),

    /// Amm V2 order detail
    AmmV2(AmmV2OrderDetail),
}

/// Submit spot order
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct SubmitSpotOrder {
    /// Market id
    pub market_id: SpotMarketId,

    /// Order
    pub order: SpotOrder,
}

/// Order scope
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub enum OrderScope {
    /// Exact order id
    Exact(OrderId),

    /// Side
    Side(OrderSide),

    /// All
    /// Note: all means all orders
    All,
}

/// Cancel spot order
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct CancelSpotOrder {
    /// Market id
    pub market_id: SpotMarketId,

    /// Cancel order scope
    pub scope: OrderScope,
}

/// Add AMM V2 liquidity
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct AddAmmV2Liquidity {
    /// Market id
    pub market_id: SpotMarketId,

    /// Base asset quantity
    pub base_asset_quantity: AssetAmount,

    /// Quote asset quantity
    pub quote_asset_quantity: AssetAmount,
}

/// Remove liquidity
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct RemoveAmmV2Liquidity {
    /// Market id
    pub market_id: SpotMarketId,

    /// Liquidity token quantity
    pub liquidity_token_quantity: AssetAmount,
}

impl From<BigUint> for OrderSide {
    fn from(side: BigUint) -> Self {
        match side {
            side if side == BigUint::from(1u8) => OrderSide::Ask,
            side if side == BigUint::from(2u8) => OrderSide::Bid,
            _ => panic!("invalid order side"),
        }
    }
}

impl Into<BigUint> for OrderSide {
    fn into(self) -> BigUint {
        match self {
            OrderSide::Ask => BigUint::from(1u8),
            OrderSide::Bid => BigUint::from(2u8),
        }
    }
}

impl_from_uint_for!(OrderSide, u8, u16, u32, u64, u128);

#[cfg(test)]
mod tests {
    use ex3_serde::{bincode, cbor};

    use super::*;

    #[test]
    fn test_submit_order_serde() {
        let submit_order = SubmitSpotOrder {
            market_id: SpotMarketId::from(1u8),
            order: SpotOrder::Spot(SpotOrderDetail {
                side: OrderSide::Ask,
                price: 100u32.into(),
                volume: 100u32.into(),
            }),
        };

        // bincode
        let encoded = bincode::serialize(&submit_order).unwrap();
        let decoded: SubmitSpotOrder = bincode::deserialize(&encoded).unwrap();
        assert_eq!(submit_order, decoded);

        // cbor
        let encoded = cbor::serialize(&submit_order).unwrap();
        let decoded: SubmitSpotOrder = cbor::deserialize(&encoded).unwrap();
        assert_eq!(submit_order, decoded);
    }

    #[test]
    fn test_cancel_order_serde() {
        let cancel_order = CancelSpotOrder {
            market_id: SpotMarketId::from(1u8),
            scope: OrderScope::Exact(OrderId::from(1u8)),
        };

        // bincode
        let encoded = bincode::serialize(&cancel_order).unwrap();
        let decoded: CancelSpotOrder = bincode::deserialize(&encoded).unwrap();
        assert_eq!(cancel_order, decoded);

        // cbor
        let encoded = cbor::serialize(&cancel_order).unwrap();
        let decoded: CancelSpotOrder = cbor::deserialize(&encoded).unwrap();
        assert_eq!(cancel_order, decoded);
    }

    #[test]
    fn test_add_amm_v2_liquidity_serde() {
        let add_liquidity = AddAmmV2Liquidity {
            market_id: SpotMarketId::from(1u8),
            base_asset_quantity: AssetAmount::from(1u8),
            quote_asset_quantity: AssetAmount::from(1u8),
        };

        // bincode
        let encoded = bincode::serialize(&add_liquidity).unwrap();
        let decoded: AddAmmV2Liquidity = bincode::deserialize(&encoded).unwrap();
        assert_eq!(add_liquidity, decoded);

        // cbor
        let encoded = cbor::serialize(&add_liquidity).unwrap();
        let decoded: AddAmmV2Liquidity = cbor::deserialize(&encoded).unwrap();
        assert_eq!(add_liquidity, decoded);
    }

    #[test]
    fn test_remove_amm_v2_liquidity_serde() {
        let remove_liquidity = RemoveAmmV2Liquidity {
            market_id: SpotMarketId::from(1u8),
            liquidity_token_quantity: AssetAmount::from(1u8),
        };

        // bincode
        let encoded = bincode::serialize(&remove_liquidity).unwrap();
        let decoded: RemoveAmmV2Liquidity = bincode::deserialize(&encoded).unwrap();
        assert_eq!(remove_liquidity, decoded);

        // cbor
        let encoded = cbor::serialize(&remove_liquidity).unwrap();
        let decoded: RemoveAmmV2Liquidity = cbor::deserialize(&encoded).unwrap();
        assert_eq!(remove_liquidity, decoded);
    }
}