pyth_lazer_publisher_sdk/
lib.rs

1use std::{collections::BTreeMap, time::Duration};
2
3use ::protobuf::MessageField;
4use anyhow::{bail, ensure, Context};
5use humantime::format_duration;
6use protobuf::dynamic_value::{dynamic_value, DynamicValue};
7use pyth_lazer_protocol::router::TimestampUs;
8
9pub mod transaction_envelope {
10    pub use crate::protobuf::transaction_envelope::*;
11}
12
13pub mod transaction {
14    pub use crate::protobuf::pyth_lazer_transaction::*;
15}
16
17pub mod publisher_update {
18    pub use crate::protobuf::publisher_update::*;
19}
20
21pub mod governance_instruction {
22    pub use crate::protobuf::governance_instruction::*;
23}
24
25#[allow(rustdoc::broken_intra_doc_links)]
26mod protobuf;
27
28impl DynamicValue {
29    pub fn try_option_from_serde(value: serde_value::Value) -> anyhow::Result<Option<Self>> {
30        match value {
31            serde_value::Value::Option(value) => {
32                if let Some(value) = value {
33                    Ok(Some((*value).try_into()?))
34                } else {
35                    Ok(None)
36                }
37            }
38            value => Ok(Some(value.try_into()?)),
39        }
40    }
41
42    pub fn to_timestamp(&self) -> anyhow::Result<TimestampUs> {
43        let value = self.value.as_ref().context("missing DynamicValue.value")?;
44        match value {
45            dynamic_value::Value::TimestampValue(ts) => Ok(ts.try_into()?),
46            _ => bail!("expected timestamp, got {:?}", self),
47        }
48    }
49
50    pub fn to_duration(&self) -> anyhow::Result<Duration> {
51        let value = self.value.as_ref().context("missing DynamicValue.value")?;
52        match value {
53            dynamic_value::Value::DurationValue(duration) => Ok(duration.clone().into()),
54            _ => bail!("expected duration, got {:?}", self),
55        }
56    }
57}
58
59impl TryFrom<serde_value::Value> for DynamicValue {
60    type Error = anyhow::Error;
61
62    fn try_from(value: serde_value::Value) -> Result<Self, Self::Error> {
63        let converted = match value {
64            serde_value::Value::Bool(value) => dynamic_value::Value::BoolValue(value),
65            serde_value::Value::U8(value) => dynamic_value::Value::UintValue(value.into()),
66            serde_value::Value::U16(value) => dynamic_value::Value::UintValue(value.into()),
67            serde_value::Value::U32(value) => dynamic_value::Value::UintValue(value.into()),
68            serde_value::Value::U64(value) => dynamic_value::Value::UintValue(value),
69            serde_value::Value::I8(value) => dynamic_value::Value::IntValue(value.into()),
70            serde_value::Value::I16(value) => dynamic_value::Value::IntValue(value.into()),
71            serde_value::Value::I32(value) => dynamic_value::Value::IntValue(value.into()),
72            serde_value::Value::I64(value) => dynamic_value::Value::IntValue(value),
73            serde_value::Value::F32(value) => dynamic_value::Value::DoubleValue(value.into()),
74            serde_value::Value::F64(value) => dynamic_value::Value::DoubleValue(value),
75            serde_value::Value::Char(value) => dynamic_value::Value::StringValue(value.to_string()),
76            serde_value::Value::String(value) => dynamic_value::Value::StringValue(value),
77            serde_value::Value::Bytes(value) => dynamic_value::Value::BytesValue(value),
78            serde_value::Value::Seq(values) => {
79                let mut items = Vec::new();
80                for value in values {
81                    items.push(value.try_into()?);
82                }
83                dynamic_value::Value::List(dynamic_value::List {
84                    items,
85                    special_fields: Default::default(),
86                })
87            }
88            serde_value::Value::Map(values) => {
89                let mut items = Vec::new();
90                for (key, value) in values {
91                    let key = match key {
92                        serde_value::Value::String(key) => key,
93                        _ => bail!("unsupported key type: expected string, got {:?}", key),
94                    };
95                    items.push(dynamic_value::MapItem {
96                        key: Some(key),
97                        value: MessageField::some(value.try_into()?),
98                        special_fields: Default::default(),
99                    })
100                }
101                dynamic_value::Value::Map(dynamic_value::Map {
102                    items,
103                    special_fields: Default::default(),
104                })
105            }
106            serde_value::Value::Unit
107            | serde_value::Value::Option(_)
108            | serde_value::Value::Newtype(_) => bail!("unsupported type: {:?}", value),
109        };
110        Ok(DynamicValue {
111            value: Some(converted),
112            special_fields: Default::default(),
113        })
114    }
115}
116
117impl TryFrom<DynamicValue> for serde_value::Value {
118    type Error = anyhow::Error;
119
120    fn try_from(value: DynamicValue) -> Result<Self, Self::Error> {
121        let value = value.value.context("missing DynamicValue.value")?;
122        match value {
123            dynamic_value::Value::StringValue(value) => Ok(serde_value::Value::String(value)),
124            dynamic_value::Value::DoubleValue(value) => Ok(serde_value::Value::F64(value)),
125            dynamic_value::Value::UintValue(value) => Ok(serde_value::Value::U64(value)),
126            dynamic_value::Value::IntValue(value) => Ok(serde_value::Value::I64(value)),
127            dynamic_value::Value::BoolValue(value) => Ok(serde_value::Value::Bool(value)),
128            dynamic_value::Value::BytesValue(value) => Ok(serde_value::Value::Bytes(value)),
129            dynamic_value::Value::DurationValue(duration) => {
130                let s: Duration = duration.into();
131                Ok(serde_value::Value::String(format_duration(s).to_string()))
132            }
133            dynamic_value::Value::TimestampValue(ts) => {
134                let ts = TimestampUs::try_from(&ts)?;
135                Ok(serde_value::Value::U64(ts.0))
136            }
137            dynamic_value::Value::List(list) => {
138                let mut output = Vec::new();
139                for item in list.items {
140                    output.push(item.try_into()?);
141                }
142                Ok(serde_value::Value::Seq(output))
143            }
144            dynamic_value::Value::Map(map) => {
145                let mut output = BTreeMap::new();
146                for item in map.items {
147                    let key = item.key.context("missing DynamicValue.MapItem.key")?;
148                    let value = item
149                        .value
150                        .into_option()
151                        .context("missing DynamicValue.MapItem.value")?
152                        .try_into()?;
153                    let old = output.insert(serde_value::Value::String(key), value);
154                    ensure!(old.is_none(), "duplicate DynamicValue.MapItem.key");
155                }
156                Ok(serde_value::Value::Map(output))
157            }
158        }
159    }
160}