lyquor_primitives/
lib.rs

1extern crate self as lyquor_primitives;
2pub extern crate serde;
3
4use std::fmt;
5use std::sync::Arc;
6
7pub use alloy_primitives::hex;
8pub use alloy_primitives::{self, Address, B256, U32, U64, U128, U256, address, uint};
9pub use blake3;
10pub use bytes::{self, Bytes};
11pub use cb58;
12pub use serde::{Deserialize, Serialize};
13use typed_builder::TypedBuilder;
14
15mod id;
16pub mod oracle;
17pub use id::{LyquidID, LyquidNumber, NodeID, RequiredLyquid};
18
19// Custom serde module for Arc<Option<T>>
20pub mod arc_option_serde {
21    use super::*;
22    use serde::{Deserialize, Deserializer, Serialize, Serializer};
23
24    pub fn serialize<T, S>(value: &Option<Arc<T>>, serializer: S) -> Result<S::Ok, S::Error>
25    where
26        T: Serialize,
27        S: Serializer,
28    {
29        match value {
30            Some(arc) => Some(arc.as_ref()).serialize(serializer),
31            None => Option::<&T>::None.serialize(serializer),
32        }
33    }
34
35    pub fn deserialize<'de, T, D>(deserializer: D) -> Result<Option<Arc<T>>, D::Error>
36    where
37        T: Deserialize<'de>,
38        D: Deserializer<'de>,
39    {
40        let opt = Option::<T>::deserialize(deserializer)?;
41        Ok(opt.map(Arc::new))
42    }
43}
44
45pub type Hash = blake3::Hash;
46
47// Network definitions moved to lyquor-api::profile.
48
49/// Position of a slot in the sequencer's backend.
50///
51/// Typically, a sequencing backend may be a chain that carries Lyquid slots in some of its blocks.
52/// This means the [SlotNumber]s do not necessarily correspond to continuous [ChainPos] in the sequencing backend.
53#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
54pub struct ChainPos(u128);
55
56impl ChainPos {
57    pub const ZERO: Self = Self(0);
58    pub fn new(block_position: u64, block_index: u32) -> Self {
59        Self((block_position as u128) << 32 | (block_index as u128))
60    }
61
62    #[inline(always)]
63    pub fn block(&self) -> u64 {
64        (self.0 >> 32) as u64
65    }
66
67    #[inline(always)]
68    pub fn next_block(&self) -> Self {
69        Self(((self.0 >> 32) + 1) << 32)
70    }
71}
72
73impl fmt::Display for ChainPos {
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
75        write!(f, "(block={}, log={})", self.0 >> 32, self.0 as u32)
76    }
77}
78
79impl fmt::Debug for ChainPos {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
81        fmt::Display::fmt(self, f)
82    }
83}
84
85#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Debug)]
86pub enum InputABI {
87    Lyquor,
88    Eth,
89}
90
91#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
92pub struct HashBytes(Hash);
93
94impl HashBytes {
95    pub fn new(hash: Hash) -> Self {
96        Self(hash)
97    }
98
99    pub fn into_inner(self) -> Hash {
100        self.0
101    }
102}
103
104impl std::ops::Deref for HashBytes {
105    type Target = Hash;
106    fn deref(&self) -> &Hash {
107        &self.0
108    }
109}
110
111impl From<[u8; 32]> for HashBytes {
112    fn from(hash: [u8; 32]) -> Self {
113        Self(hash.into())
114    }
115}
116
117impl From<HashBytes> for [u8; 32] {
118    fn from(hash: HashBytes) -> Self {
119        hash.0.into()
120    }
121}
122
123impl From<Hash> for HashBytes {
124    fn from(hash: Hash) -> Self {
125        Self(hash)
126    }
127}
128
129impl From<HashBytes> for Hash {
130    fn from(hash_bytes: HashBytes) -> Self {
131        hash_bytes.0
132    }
133}
134
135impl Serialize for HashBytes {
136    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
137    where
138        S: serde::Serializer,
139    {
140        let bytes: &[u8; 32] = self.0.as_bytes();
141        serializer.serialize_bytes(bytes)
142    }
143}
144
145impl<'de> Deserialize<'de> for HashBytes {
146    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
147    where
148        D: serde::Deserializer<'de>,
149    {
150        use serde::de::Error;
151        let bytes = <Vec<u8>>::deserialize(deserializer)?;
152        if bytes.len() != 32 {
153            return Err(D::Error::custom(format!(
154                "Expected 32 bytes for HashBytes, got {}",
155                bytes.len()
156            )));
157        }
158        let mut array = [0u8; 32];
159        array.copy_from_slice(&bytes);
160        Ok(HashBytes(blake3::Hash::from(array)))
161    }
162}
163
164#[derive(Serialize, Deserialize, PartialEq, Clone, TypedBuilder)]
165pub struct CallParams {
166    /// The ultimate origin of the call (the transaction signer, for example if the call comes from
167    /// the chain. The default is zero address when unused.
168    #[builder(default = Address::ZERO)]
169    pub origin: Address,
170    /// The direct caller.
171    pub caller: Address,
172    #[builder(default = GROUP_DEFAULT.into())]
173    pub group: String,
174    pub method: String,
175    pub input: Bytes,
176    #[builder(default = InputABI::Lyquor)]
177    pub abi: InputABI,
178}
179
180impl Eq for CallParams {}
181
182impl fmt::Debug for CallParams {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
184        write!(
185            f,
186            "CallParams(caller={}, origin={}, group={}, method={}, input={}, abi={:?})",
187            self.caller,
188            self.origin,
189            self.group,
190            self.method,
191            hex::encode(&self.input),
192            self.abi
193        )
194    }
195}
196
197pub const GROUP_DEFAULT: &str = "main";
198pub const GROUP_NODE: &str = "node";
199pub const GROUP_UPC_PREPARE: &str = "upc::prepare";
200pub const GROUP_UPC_REQ: &str = "upc::request";
201pub const GROUP_UPC_RESP: &str = "upc::response";
202
203pub type LyteLogTopic = B256;
204
205#[derive(Serialize, Deserialize, Clone)]
206pub struct LyteLog {
207    pub topics: [Option<Box<LyteLogTopic>>; 4],
208    pub data: Bytes,
209}
210
211impl LyteLog {
212    pub fn new_from_tagged_value<V: Serialize>(tag: &str, value: &V) -> Self {
213        let topic0 = Box::new(Self::tagged_value_topic(tag));
214        Self {
215            topics: [Some(topic0), None, None, None],
216            data: encode_object(value).into(),
217        }
218    }
219
220    pub fn tagged_value_topic(tag: &str) -> LyteLogTopic {
221        let mut hasher = blake3::Hasher::new();
222        hasher.update(tag.as_bytes());
223        let topic: [u8; 32] = hasher.finalize().into();
224        topic.into()
225    }
226}
227
228#[derive(Serialize, Deserialize, Clone, Debug)]
229pub struct RegisterEvent {
230    pub id: LyquidID,
231    pub deps: Vec<LyquidID>,
232}
233
234impl fmt::Debug for LyteLog {
235    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
236        write!(
237            f,
238            "LyteLog(topics={}, data=<{} bytes>)",
239            self.topics
240                .iter()
241                .map(|t| match t {
242                    Some(t) => t.to_string(),
243                    None => "_".into(),
244                })
245                .collect::<Vec<_>>()
246                .join(", "),
247            self.data.len()
248        )
249    }
250}
251
252pub fn decode_object<T: for<'a> Deserialize<'a>>(raw: &[u8]) -> Option<T> {
253    postcard::from_bytes(raw).ok()
254}
255
256pub fn encode_object<T: Serialize + ?Sized>(obj: &T) -> Vec<u8> {
257    postcard::to_stdvec(obj).expect("postcard serialization failed")
258}
259
260pub fn encode_object_with_prefix<T: Serialize + ?Sized>(prefix: &[u8], obj: &T) -> Vec<u8> {
261    let mut vec = Vec::with_capacity(prefix.len() + core::mem::size_of_val(obj));
262    vec.extend_from_slice(prefix);
263    postcard::to_io(obj, &mut vec).expect("postcard serialization failed");
264    vec
265}
266
267#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
268pub enum StateCategory {
269    Network,
270    Instance,
271}
272
273#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Copy, Clone)]
274#[serde(rename_all = "camelCase")]
275pub enum ConsoleSink {
276    StdOut,
277    StdErr,
278}
279
280pub fn encode_method_name(cat_prefix: &str, group: &str, method: &str) -> String {
281    let mut output = cat_prefix.to_string();
282    output.push('_');
283    cb58::bs58::encode(group.as_bytes()).onto(&mut output).unwrap();
284    output.push('_');
285    output.push_str(method);
286    output
287}
288
289#[doc(hidden)]
290#[macro_export]
291macro_rules! object_by_fields_ {
292    ($serde_crate: tt, $($var:ident: $type:ty = $val:expr),*) => {{
293        #[allow(non_camel_case_types)]
294        #[derive($crate::Serialize, Clone)]
295        #[serde(crate = $serde_crate)]
296        struct parameters { $($var:$type),* }
297        parameters { $($var: $val),* }
298    }};
299}
300
301#[macro_export]
302macro_rules! object_by_fields {
303    ($($token: tt)*) => {{
304        $crate::object_by_fields_!("lyquor_primitives::serde", $($token)*)
305    }};
306}
307
308#[doc(hidden)]
309#[macro_export]
310macro_rules! encode_by_fields_ {
311    ($serde_crate: tt, $($var:ident: $type:ty = $val:expr),*) => {{
312        $crate::encode_object(&$crate::object_by_fields_!($serde_crate, $($var: $type = $val),*))
313    }};
314    ($serde_crate: tt, $($var:ident: $type:ty),*) => {{
315        $crate::encode_object(&$crate::object_by_fields_!($serde_crate, $($var: $type = $var),*))
316    }};
317}
318
319#[macro_export]
320macro_rules! encode_by_fields {
321    ($($token: tt)*) => {{
322        $crate::encode_by_fields_!("lyquor_primitives::serde", $($token)*)
323    }};
324}
325
326#[macro_export]
327macro_rules! decode_by_fields {
328    ($encoded:expr, $($var:ident: $type:ty),*) => {{
329        #[allow(non_camel_case_types)]
330        #[derive($crate::Deserialize)]
331        #[serde(crate = "lyquor_primitives::serde")]
332        struct parameters { $($var:$type),* }
333        $crate::decode_object::<parameters>($encoded)
334    }};
335}
336
337#[derive(Serialize, Deserialize, Debug)]
338pub struct Range<T> {
339    pub start: Option<T>,
340    pub end: Option<T>,
341}
342
343#[macro_export]
344macro_rules! debug_struct_name {
345    ($t:ty) => {
346        impl std::fmt::Debug for $t {
347            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
348                f.write_str(stringify!($t))
349            }
350        }
351    };
352}
353
354/// Signature scheme used when requesting signatures from the host.
355#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Debug)]
356pub enum Cipher {
357    Ed25519,
358    Secp256k1,
359}