rust_okx/api/finance/requests/
savings.rs1use serde::Serialize;
2
3use crate::model::{
4 RequestValidationError, ValidateRequest, decimal_string_range, non_empty, one_of,
5 optional_positive_decimal_string, positive_decimal_string, reject_when_present,
6};
7
8#[derive(Debug, Clone, Serialize)]
10pub struct SavingsPurchaseRedemptionRequest {
11 ccy: String,
12 amt: String,
13 side: String,
14 #[serde(skip_serializing_if = "Option::is_none")]
15 rate: Option<String>,
16}
17
18impl SavingsPurchaseRedemptionRequest {
19 pub fn new(ccy: impl Into<String>, amt: impl Into<String>, side: impl Into<String>) -> Self {
23 Self {
24 ccy: ccy.into(),
25 amt: amt.into(),
26 side: side.into(),
27 rate: None,
28 }
29 }
30
31 pub fn rate(mut self, rate: impl Into<String>) -> Self {
35 self.rate = Some(rate.into());
36 self
37 }
38}
39
40impl ValidateRequest for SavingsPurchaseRedemptionRequest {
41 fn validate(&self) -> Result<(), RequestValidationError> {
42 non_empty("ccy", &self.ccy)?;
43 positive_decimal_string("amt", &self.amt)?;
44 one_of(
45 "side",
46 &self.side,
47 &["purchase", "redempt"],
48 "purchase or redempt",
49 )?;
50
51 if self.side == "redempt" {
52 reject_when_present("rate", self.rate.as_ref(), "side is redempt")?;
53 }
54 if let Some(rate) = self.rate.as_deref() {
55 optional_positive_decimal_string("rate", Some(rate))?;
56 decimal_string_range("rate", rate, 0.01, 3.65, "0.01", "3.65")?;
57 }
58 Ok(())
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn redemption_rejects_lending_rate() {
68 let request = SavingsPurchaseRedemptionRequest::new("USDT", "1", "redempt").rate("0.02");
69 assert!(request.validate().is_err());
70 }
71
72 #[test]
73 fn purchase_rate_must_be_in_documented_range() {
74 let request = SavingsPurchaseRedemptionRequest::new("USDT", "1", "purchase").rate("3.66");
75 assert!(request.validate().is_err());
76 }
77}