lyquor_primitives/
oracle.rs

1use super::*;
2
3#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Debug)]
4pub enum OracleTarget {
5    // Lyquor network fn
6    LVM(LyquidID),
7    // EVM-based sequence backend
8    EVM(Address),
9}
10
11impl OracleTarget {
12    pub fn cipher(&self) -> Cipher {
13        match self {
14            Self::EVM(_) => Cipher::Secp256k1,
15            Self::LVM(_) => Cipher::Ed25519,
16        }
17    }
18}
19
20/// Contains all fields needed to define a call other than the call parameters.
21#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Debug)]
22pub struct OracleHeader {
23    /// Node that proposed the call for certification.
24    pub proposer: NodeID,
25    /// Destination of the call (where it will be finally executed).
26    pub target: OracleTarget,
27    // TODO: add target chain ID
28    /// Oracle config digest.
29    pub config_hash: HashBytes,
30    /// Epoch number used by OracleDest.
31    pub epoch: u32,
32    /// Random nonce that uniquely identifies the certified call within an epoch.
33    pub nonce: HashBytes,
34}
35
36pub type SignerID = u32;
37
38#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
39pub struct OracleSigner {
40    pub id: SignerID,
41    pub key: Bytes,
42}
43
44#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
45pub struct OracleConfig {
46    pub committee: Vec<OracleSigner>,
47    pub threshold: u16,
48}
49
50impl OracleConfig {
51    pub fn to_hash(&self) -> Hash {
52        blake3::hash(&encode_object(self))
53    }
54}
55
56#[derive(Serialize, Deserialize)]
57pub struct ValidatePreimage {
58    pub header: OracleHeader,
59    pub params: CallParams,
60    pub approval: bool,
61}
62
63impl ValidatePreimage {
64    const PREFIX: &'static [u8] = b"lyquor_validate_preimage_v1\0";
65
66    pub fn to_preimage(&self) -> Vec<u8> {
67        encode_object_with_prefix(Self::PREFIX, self)
68    }
69
70    pub fn to_hash(&self) -> Hash {
71        blake3::hash(&self.to_preimage())
72    }
73}
74
75/// Oracle certificate that could be sequenced.
76#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
77pub struct OracleCert {
78    pub header: OracleHeader,
79    /// If Some, a new config is agreed upon for this and following certificates, and becomes
80    /// effective until the next update.
81    pub new_config: Option<OracleConfig>,
82    /// Signers for the signatures in order.
83    pub signers: Vec<SignerID>,
84    /// Vote signatures.
85    pub signatures: Vec<Bytes>,
86}
87
88pub mod eth {
89    use alloy_sol_types::{SolType, sol};
90    sol! {
91        struct OracleHeader {
92            bytes32 proposer;
93            address target;
94            bytes32 configHash;
95            uint32 epoch;
96            bytes32 nonce;
97        }
98
99        struct OracleSigner {
100            uint32 id;
101            address key;
102        }
103
104        struct OracleConfig {
105            OracleSigner[] committee;
106            uint16 threshold;
107        }
108
109        struct ValidatePreimage {
110            OracleHeader header;
111            string method; // Invoked method of the contract.
112            bytes input; // Raw input for the call.
113            bool approval; // Should always be true signed by multi-sigs that make up the final cert.
114        }
115    }
116
117    impl OracleConfig {
118        pub fn to_hash(&self) -> super::Hash {
119            alloy_primitives::keccak256(&OracleConfig::abi_encode(self)).0.into()
120        }
121    }
122
123    impl Default for OracleConfig {
124        fn default() -> Self {
125            Self {
126                committee: Default::default(),
127                threshold: Default::default(),
128            }
129        }
130    }
131
132    impl ValidatePreimage {
133        const PREFIX: &'static [u8] = b"lyquor_validate_preimage_v1\0";
134
135        pub fn to_preimage(&self) -> Vec<u8> {
136            let mut buf = Vec::from(Self::PREFIX);
137            buf.extend_from_slice(&Self::abi_encode(self));
138            buf
139        }
140
141        pub fn to_hash(&self) -> super::Hash {
142            alloy_primitives::keccak256(&self.to_preimage()).0.into()
143        }
144    }
145
146    impl TryFrom<super::OracleHeader> for OracleHeader {
147        type Error = ();
148
149        fn try_from(oh: super::OracleHeader) -> Result<Self, ()> {
150            Ok(OracleHeader {
151                proposer: <[u8; 32]>::from(oh.proposer).into(),
152                target: match oh.target {
153                    super::OracleTarget::LVM(_) => return Err(()),
154                    super::OracleTarget::EVM(t) => t,
155                },
156                configHash: <[u8; 32]>::from(oh.config_hash).into(),
157                epoch: oh.epoch,
158                nonce: <[u8; 32]>::from(oh.nonce).into(),
159            })
160        }
161    }
162
163    impl From<OracleHeader> for super::OracleHeader {
164        fn from(oh: OracleHeader) -> Self {
165            Self {
166                proposer: <[u8; 32]>::from(oh.proposer).into(),
167                target: super::OracleTarget::EVM(oh.target),
168                config_hash: <[u8; 32]>::from(oh.configHash).into(),
169                epoch: oh.epoch,
170                nonce: <[u8; 32]>::from(oh.nonce).into(),
171            }
172        }
173    }
174
175    impl From<super::OracleConfig> for OracleConfig {
176        fn from(oc: super::OracleConfig) -> Self {
177            Self {
178                committee: oc
179                    .committee
180                    .into_iter()
181                    .map(|s| OracleSigner {
182                        id: s.id,
183                        key: s.key.as_ref().try_into().unwrap(),
184                    })
185                    .collect(),
186                threshold: oc.threshold as u16,
187            }
188        }
189    }
190
191    impl TryFrom<super::ValidatePreimage> for ValidatePreimage {
192        type Error = ();
193        fn try_from(om: super::ValidatePreimage) -> Result<Self, ()> {
194            Ok(Self {
195                header: om.header.try_into()?,
196                method: om.params.method,
197                input: om.params.input.into(),
198                approval: om.approval,
199            })
200        }
201    }
202}