tempo_precompiles/stablecoin_exchange/
error.rs

1/// Errors that can occur when working with orders.
2#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
3pub enum OrderError {
4    /// Flip tick constraint violated for a bid flip order.
5    /// For bids: flip_tick must be > tick
6    #[error(
7        "invalid flip tick for bid order: flip_tick ({flip_tick}) must be greater than tick ({tick})"
8    )]
9    InvalidBidFlipTick {
10        /// The order's tick
11        tick: i16,
12        /// The invalid flip_tick value
13        flip_tick: i16,
14    },
15
16    /// Flip tick constraint violated for an ask flip order.
17    /// For asks: flip_tick must be < tick
18    #[error(
19        "invalid flip tick for ask order: flip_tick ({flip_tick}) must be less than tick ({tick})"
20    )]
21    InvalidAskFlipTick {
22        /// The order's tick
23        tick: i16,
24        /// The invalid flip_tick value
25        flip_tick: i16,
26    },
27
28    /// Attempted to create a flipped order from a non-flip order
29    #[error("cannot create flipped order from a non-flip order")]
30    NotAFlipOrder,
31
32    /// Attempted to create a flipped order from an order that is not fully filled
33    #[error("order must be fully filled to flip, but {remaining} amount remains")]
34    OrderNotFullyFilled {
35        /// Remaining amount that needs to be filled
36        remaining: u128,
37    },
38
39    /// Attempted to fill more than the remaining amount
40    #[error("cannot fill {requested} when only {available} is available")]
41    FillAmountExceedsRemaining {
42        /// Amount requested to fill
43        requested: u128,
44        /// Amount available to fill
45        available: u128,
46    },
47
48    /// Tick value is out of valid bounds
49    #[error("tick {tick} is out of bounds (min: {min}, max: {max})")]
50    InvalidTick {
51        /// The invalid tick value
52        tick: i16,
53        /// Minimum valid tick
54        min: i16,
55        /// Maximum valid tick
56        max: i16,
57    },
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn test_invalid_flip_tick_bid() {
66        let err = OrderError::InvalidBidFlipTick {
67            tick: 5,
68            flip_tick: 3,
69        };
70        let msg = err.to_string();
71        assert!(msg.contains("bid"));
72        assert!(msg.contains("greater than"));
73        assert!(msg.contains("5"));
74        assert!(msg.contains("3"));
75    }
76
77    #[test]
78    fn test_invalid_flip_tick_ask() {
79        let err = OrderError::InvalidAskFlipTick {
80            tick: 5,
81            flip_tick: 7,
82        };
83        let msg = err.to_string();
84        assert!(msg.contains("ask"));
85        assert!(msg.contains("less than"));
86        assert!(msg.contains("5"));
87        assert!(msg.contains("7"));
88    }
89
90    #[test]
91    fn test_not_a_flip_order() {
92        let err = OrderError::NotAFlipOrder;
93        assert_eq!(
94            err.to_string(),
95            "cannot create flipped order from a non-flip order"
96        );
97    }
98
99    #[test]
100    fn test_order_not_fully_filled() {
101        let err = OrderError::OrderNotFullyFilled { remaining: 500 };
102        let msg = err.to_string();
103        assert!(msg.contains("500"));
104        assert!(msg.contains("must be fully filled"));
105    }
106
107    #[test]
108    fn test_fill_amount_exceeds_remaining() {
109        let err = OrderError::FillAmountExceedsRemaining {
110            requested: 1000,
111            available: 600,
112        };
113        let msg = err.to_string();
114        assert!(msg.contains("1000"));
115        assert!(msg.contains("600"));
116    }
117
118    #[test]
119    fn test_invalid_tick() {
120        let err = OrderError::InvalidTick {
121            tick: 3000,
122            min: -2000,
123            max: 2000,
124        };
125        let msg = err.to_string();
126        assert_eq!(msg, "tick 3000 is out of bounds (min: -2000, max: 2000)");
127    }
128}