use serde::{Deserialize, Serialize};
use super::wire::{hex32, hexbytes};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActionResponse {
pub result: ActionResult,
#[serde(with = "hexbytes", default)]
pub signature: Vec<u8>,
#[serde(rename = "proxySignature", with = "hexbytes", default)]
pub proxy_signature: Vec<u8>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActionResult {
#[serde(with = "hex32")]
pub id: [u8; 32],
#[serde(rename = "submissionTag")]
pub submission_tag: String,
pub status: u8,
pub log: String,
#[serde(rename = "opType", with = "hex32")]
pub op_type: [u8; 32],
#[serde(rename = "opCommand", with = "hex32")]
pub op_command: [u8; 32],
pub version: String,
#[serde(with = "hexbytes", default)]
pub data: Vec<u8>,
}
impl ActionResult {
pub fn ok(&self) -> bool {
self.status == 1
}
pub fn decode<T: serde::de::DeserializeOwned>(&self) -> eyre::Result<T> {
if self.data.is_empty() {
eyre::bail!(
"action result has no data (status={}, log={})",
self.status,
self.log
);
}
Ok(serde_json::from_slice(&self.data)?)
}
pub fn data_bytes(&self) -> &[u8] {
&self.data
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn decodes_hex_data_to_json() {
let json = br#"{"orderId":"0x07","orderInBook":true,"fills":0}"#;
let envelope = serde_json::json!({
"result": {
"id": "0x".to_string() + &"00".repeat(32),
"submissionTag": "submit",
"status": 1u8,
"log": "ok",
"opType": "0x".to_string() + &"00".repeat(32),
"opCommand": "0x".to_string() + &"00".repeat(32),
"version": "0.1.0",
"data": format!("0x{}", hex::encode(json)),
},
"signature": "0x",
"proxySignature": "0x",
});
let resp: ActionResponse = serde_json::from_value(envelope).unwrap();
assert!(resp.result.ok());
let po: super::super::payloads::PlaceOrderResponse = resp.result.decode().unwrap();
assert_eq!(po.order_id, "0x07");
assert!(po.order_in_book);
}
#[test]
fn failed_status_surfaces_log() {
let envelope = serde_json::json!({
"result": {
"id": "0x".to_string() + &"00".repeat(32),
"submissionTag": "submit",
"status": 0u8,
"log": "error: unsupported direct command",
"opType": "0x".to_string() + &"00".repeat(32),
"opCommand": "0x".to_string() + &"00".repeat(32),
"version": "0.1.0",
"data": "0x",
}
});
let resp: ActionResponse = serde_json::from_value(envelope).unwrap();
assert!(!resp.result.ok());
assert!(resp.result.decode::<serde_json::Value>().is_err());
}
}