Skip to main content

rialo_oracle_processor_interface/
instruction.rs

1// Copyright (c) Subzero Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Instructions for the Oracle Processor program.
5//!
6//! This module defines the instructions for communicating resulting data from Oracles.
7
8use rialo_s_instruction::{AccountMeta, Instruction};
9use rialo_s_program::system_program;
10use rialo_s_pubkey::Pubkey;
11use rialo_types::{Nonce, OracleId};
12use serde::{Deserialize, Serialize};
13
14pub use crate::state::OracleUpdate;
15
16/// Static seed for oracle update PDA derivation
17pub const ORACLE_REPORT_SEED: &[u8] = b"oracle_report";
18
19/// Static seed for payer PDA derivation
20pub const ORACLE_REPORT_PAYER_SEED: &[u8] = b"report_payer";
21
22/// Default payer for oracle updates - synchronized with `svm-execution/src/bank.rs`
23pub const ORACLE_UPDATE_PAYER: Pubkey =
24    Pubkey::from_str_const("Qrac1eUpdatePayer11111111111111111111111111");
25
26/// Instructions supported by the Oracle Processor program. Made to report oracle updates from
27/// validators.
28#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
29pub enum OracleProcessorInstruction {
30    /// Report oracle updates from validators
31    Report {
32        /// Unique identifier for the oracle
33        oracle_id: OracleId,
34        /// Updates from each validator
35        updates: Vec<OracleUpdate>,
36    },
37}
38
39impl OracleProcessorInstruction {
40    /// Creates an instruction for oracle reporting.
41    ///
42    /// This function creates an instruction that will report an oracle update and emit
43    /// an event that subscribers can listen to.
44    ///
45    /// # Arguments
46    ///
47    /// * `payer` - The public key of the payer
48    /// * `oracle_id` - The ID of the oracle
49    /// * `updates` - A vector of oracle updates
50    ///
51    /// # Returns
52    ///
53    /// An instruction that stores oracle data in a PDA and emits an event.
54    /// Subscribers can listen to the instance-specific topic to receive
55    /// notifications when oracle reports are stored.
56    ///
57    /// # Accounts
58    ///
59    /// * `[0]` - Payer account (signer, writable)
60    /// * `[1]` - Report PDA account (writable)
61    /// * `[2]` - Event PDA account (writable)
62    /// * `[3]` - System program (readonly)
63    pub fn report(payer: Pubkey, oracle_id: OracleId, updates: Vec<OracleUpdate>) -> Instruction {
64        use rialo_events_core::derive_event_address;
65
66        use crate::event::OracleReportEvent;
67
68        // Derive the PDA for the report account
69        let (report_key, _bump) = derive_report_address(&oracle_id.creator, oracle_id.nonce);
70
71        // Derive the PDA for the event account using the new standardized method
72        let event = OracleReportEvent::new(oracle_id);
73        let (event_key, _bump) = derive_event_address(&event.instance_topic(), &crate::id());
74
75        Instruction::new_with_bincode(
76            crate::id(),
77            &OracleProcessorInstruction::Report { oracle_id, updates },
78            vec![
79                AccountMeta::new(payer, true),
80                AccountMeta::new(report_key, false),
81                AccountMeta::new(event_key, false),
82                AccountMeta::new_readonly(system_program::id(), false),
83            ],
84        )
85    }
86}
87
88/// Derive the PDA for an oracle report account
89///
90/// # Arguments
91///
92/// * `creator` - The creator of the oracle
93/// * `nonce` - The nonce of the oracle
94///
95/// # Returns
96///
97/// A tuple containing the PDA and the bump seed
98pub fn derive_report_address<NONCE: Into<Nonce>>(creator: &Pubkey, nonce: NONCE) -> (Pubkey, u8) {
99    let nonce: Nonce = nonce.into();
100    Pubkey::find_program_address(
101        &[ORACLE_REPORT_SEED, &creator.to_bytes(), nonce.as_bytes()],
102        &crate::id(),
103    )
104}
105
106#[cfg(test)]
107mod tests {
108    use rialo_events_core::RialoEvent;
109    use rialo_s_pubkey::Pubkey;
110
111    use super::*;
112
113    #[derive(Default, RialoEvent)]
114    struct TestEvent {
115        name: String,
116        value: u64,
117    }
118
119    #[test]
120    fn test_report_oracle_updates() {
121        use rialo_events_core::derive_event_address;
122
123        use crate::event::OracleReportEvent;
124
125        let authority_key = [0; 96];
126        let payer = Pubkey::new_unique();
127        let data = vec![0, 1, 2, 3];
128
129        let updates = vec![OracleUpdate::new(data, authority_key)];
130        let nonce = Nonce::from(b"test-oracle-42");
131        let oracle_id = OracleId::new(payer, nonce);
132
133        // Create the instruction
134        let instruction = OracleProcessorInstruction::report(payer, oracle_id, updates.clone());
135
136        // Derive event PDA using the new standardized method
137        let event = OracleReportEvent::new(oracle_id);
138        let (expected_event_key, _) = derive_event_address(&event.instance_topic(), &crate::id());
139
140        // Check the report instruction
141        let expected_accounts = vec![
142            AccountMeta::new(payer, true),
143            AccountMeta::new(
144                derive_report_address(&oracle_id.creator, oracle_id.nonce).0,
145                false,
146            ),
147            AccountMeta::new(expected_event_key, false),
148            AccountMeta::new_readonly(system_program::id(), false),
149        ];
150
151        // Verify the instruction data
152        let expected_data = bincode::serialize(&OracleProcessorInstruction::Report {
153            oracle_id,
154            updates: updates.clone(),
155        })
156        .unwrap();
157
158        assert_eq!(instruction.data, expected_data);
159        assert_eq!(instruction.accounts, expected_accounts);
160        assert_eq!(instruction.program_id, crate::id());
161    }
162
163    #[test]
164    fn test_report_address_derivation() {
165        let oracle_creator = Pubkey::new_unique();
166        let (report_pubkey1, _) = derive_report_address(&oracle_creator, b"test-oracle-a42");
167        let (report_pubkey2, _) = derive_report_address(&oracle_creator, b"test-oracle-43");
168        assert_ne!(report_pubkey1, report_pubkey2);
169    }
170}