use serde::{Deserialize, Serialize};
use crate::types::MarketId;
use crate::wallet::Address;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct UpdateLeverage {
pub asset: MarketId,
pub leverage: u32,
pub is_isolated: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct UpdateIsolatedMargin {
pub asset: MarketId,
pub delta: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct TopUpIsolatedOnlyMargin {
pub asset: MarketId,
pub amount: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct UserPortfolioMargin {
pub enroll: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct SetDisplayName {
pub display_name: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct SetReferrer {
pub referrer: Address,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct ApproveAgent {
pub agent: Address,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub expires_at_ms: Option<u64>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct ApproveBuilderFee {
pub builder: Address,
pub max_bps: u16,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct ConvertToMultiSigUser {
pub signers: Vec<Address>,
pub threshold: u32,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct UserDexAbstraction {
pub enabled: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct UserSetAbstraction {
pub kind: u8,
pub value: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct AgentSetAbstraction {
pub user: Address,
pub kind: u8,
pub value: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct PriorityBid {
pub asset: MarketId,
pub bid_bps: u16,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn update_leverage_serializes_snake_case_integers() {
let a = UpdateLeverage {
asset: MarketId(2),
leverage: 10,
is_isolated: true,
};
let j = serde_json::to_value(a).unwrap();
assert_eq!(j["asset"], serde_json::json!(2));
assert_eq!(j["leverage"], serde_json::json!(10));
assert_eq!(j["is_isolated"], serde_json::json!(true));
assert!(j.get("isIsolated").is_none(), "no camelCase leak");
}
#[test]
fn isolated_margin_delta_rides_as_string() {
let a = UpdateIsolatedMargin {
asset: MarketId(1),
delta: "-12.5".into(),
};
let j = serde_json::to_value(&a).unwrap();
assert!(
j["delta"].is_string(),
"signed decimal must be a JSON string"
);
assert_eq!(j["delta"], serde_json::json!("-12.5"));
}
#[test]
fn approve_agent_omits_optional_fields() {
let a = ApproveAgent {
agent: Address::ZERO,
name: None,
expires_at_ms: None,
};
let j = serde_json::to_value(&a).unwrap();
assert!(j.get("name").is_none());
assert!(j.get("expires_at_ms").is_none());
let dec: ApproveAgent = serde_json::from_value(j).unwrap();
assert_eq!(a, dec);
}
#[test]
fn user_portfolio_margin_round_trips() {
let a = UserPortfolioMargin { enroll: true };
let j = serde_json::to_string(&a).unwrap();
assert_eq!(serde_json::from_str::<UserPortfolioMargin>(&j).unwrap(), a);
}
}