1use account::{create_account, increase_account_size};
2use arch_program::{
3 account::{next_account_info, AccountInfo},
4 msg,
5 program::set_return_data,
6 program_error::ProgramError,
7 pubkey::Pubkey,
8};
9
10mod account;
11mod cpi;
12mod errors;
13mod mempool_entries;
14mod mempool_entry;
15mod ops;
16mod params;
17mod state;
18mod txid;
19
20use params::*;
21use state::*;
22
23pub use {
24 cpi::*,
25 errors::CpiErrorCode,
26 mempool_entries::MempoolEntries,
27 mempool_entry::MempoolEntry,
28 saturn_mempool_oracle_sdk as sdk,
29 ops::{UpdateMempoolEntries, UpdateMempoolEntriesInstruction, UpdateMempoolEntriesOp},
30 txid::Txid,
31};
32
33#[cfg(not(feature = "no-entrypoint"))]
34use arch_program::entrypoint;
35
36pub const MEMPOOL_ORACLE_ACCOUNTS: usize = 3;
40
41pub use saturn_mempool_oracle_sdk::*;
42
43#[cfg(not(feature = "no-entrypoint"))]
44entrypoint!(process_instruction);
45
46pub fn process_instruction<'a>(
47 program_id: &Pubkey,
48 accounts: &'a [AccountInfo<'static>],
49 instruction_data: &[u8],
50) -> Result<(), ProgramError> {
51 msg!("starting program");
52
53 let instruction = deserialize_instruction(instruction_data)?;
54
55 msg!("Processing mempool oracle instruction");
56
57 let (info_accounts, rem_accounts) = accounts.split_at(MEMPOOL_ORACLE_ACCOUNTS);
58
59 if info_accounts.len() != MEMPOOL_ORACLE_ACCOUNTS {
60 return Err(ProgramError::NotEnoughAccountKeys);
61 }
62
63 msg!("entries ok");
64
65 let return_data: Option<Vec<u8>> = match instruction {
66 UpdateMempoolEntriesInstruction::InitializeProgram => {
67 validate_pda_accounts(*program_id, info_accounts)?;
68
69 if rem_accounts.len() != 3 {
70 return Err(ProgramError::NotEnoughAccountKeys);
71 }
72
73 if *rem_accounts[0].key != OWNER_PUBKEY {
74 msg!(
75 "invalid signer: {:x} != {:x}",
76 rem_accounts[0].key,
77 OWNER_PUBKEY
78 );
79 return Err(ProgramError::IncorrectProgramId);
80 }
81
82 assert!(rem_accounts[0].is_signer, "signer account must be a signer");
83
84 msg!("signer ok");
85
86 for (i, account) in info_accounts.iter().enumerate() {
87 let (pda, bump_seed) = mempool_pda_address(program_id, i as u32);
88
89 if *account.key != pda {
90 msg!(
91 "PDA check failed: {:?}",
92 PdaError::InvalidPda(pda, *account.key)
93 );
94 return Err(PdaError::InvalidPda(pda, *account.key))
95 .map_err(|_| ProgramError::Custom(1))?;
96 }
97
98 if account.lamports() != 0 {
99 return Err(ProgramError::AccountAlreadyInitialized);
100 }
101
102 let idx_seed = (i as u32).to_le_bytes();
104 let combined_seeds: [&[u8]; 2] = [&idx_seed, &[bump_seed]];
105 let cpi_signer_seeds: &[&[&[u8]]] = &[&combined_seeds];
106
107 create_account(
108 account,
109 &rem_accounts[1],
110 &rem_accounts[0],
111 &rem_accounts[2],
112 cpi_signer_seeds,
113 )?;
114 }
115
116 None
117 }
118 UpdateMempoolEntriesInstruction::ResizeAccounts => {
119 validate_pda_accounts(*program_id, info_accounts)?;
120
121 if rem_accounts.len() != 1 {
122 return Err(ProgramError::NotEnoughAccountKeys);
123 }
124
125 if *rem_accounts[0].key != OWNER_PUBKEY {
126 msg!(
127 "invalid signer: {:x} != {:x}",
128 rem_accounts[0].key,
129 OWNER_PUBKEY
130 );
131 return Err(ProgramError::IncorrectProgramId);
132 }
133
134 assert!(rem_accounts[0].is_signer, "signer account must be a signer");
135
136 msg!("signer ok");
137
138 let size = std::mem::size_of::<MempoolEntries>();
139 for account in info_accounts.iter() {
140 if account.lamports() == 0 {
141 return Err(ProgramError::UninitializedAccount);
142 }
143
144 increase_account_size(account, size as u32)?;
145 }
146
147 None
148 }
149 UpdateMempoolEntriesInstruction::ModifyEntries(update_mempool_entries_ops) => {
150 validate_pda_accounts(*program_id, info_accounts)?;
151
152 let mut entries = deserialize_multiple_mempool_entries(
153 &mut info_accounts.iter(),
154 MEMPOOL_ORACLE_ACCOUNTS,
155 )?;
156
157 if rem_accounts.len() != 1 {
158 return Err(ProgramError::NotEnoughAccountKeys);
159 }
160
161 if *rem_accounts[0].key != OWNER_PUBKEY {
162 msg!(
163 "invalid signer: {:x} != {:x}",
164 rem_accounts[0].key,
165 OWNER_PUBKEY
166 );
167 return Err(ProgramError::IncorrectProgramId);
168 }
169
170 assert!(rem_accounts[0].is_signer, "signer account must be a signer");
171
172 msg!("signer ok");
173
174 for op in update_mempool_entries_ops {
175 let index = op.txid()[0] as usize % MEMPOOL_ORACLE_ACCOUNTS;
176
177 match op {
178 UpdateMempoolEntriesOp::AddEntry(entry) => entries[index].add_entry(entry),
179 UpdateMempoolEntriesOp::DeleteEntry(txid) => entries[index].remove_entry(txid),
180 UpdateMempoolEntriesOp::UpdateEntry(entry) => {
181 entries[index].update_entry(entry)
182 }
183 }
184 }
185
186 None
187 }
188 UpdateMempoolEntriesInstruction::GetEntries(txids) => {
189 validate_pda_accounts(*program_id, info_accounts)?;
190
191 let entries = deserialize_multiple_mempool_entries(
192 &mut info_accounts.iter(),
193 MEMPOOL_ORACLE_ACCOUNTS,
194 )?;
195
196 let computed_entries_bytes = find_mempool_entries(&entries, &txids)?;
197 Some(computed_entries_bytes)
198 }
199 };
200
201 msg!("instruction ok");
202
203 if let Some(return_data) = return_data {
204 set_return_data(&return_data);
205 }
206
207 Ok(())
208}
209
210pub fn id() -> Pubkey {
211 Pubkey([
212 213, 44, 6, 241, 148, 65, 8, 220, 181, 85, 24, 214, 28, 42, 204, 102, 185, 34, 202, 233,
213 24, 149, 13, 242, 149, 96, 68, 183, 219, 90, 109, 163,
214 ])
215}
216
217pub const ID: Pubkey = Pubkey([
218 213, 44, 6, 241, 148, 65, 8, 220, 181, 85, 24, 214, 28, 42, 204, 102, 185, 34, 202, 233, 24,
219 149, 13, 242, 149, 96, 68, 183, 219, 90, 109, 163,
220]);
221
222pub const OWNER_PUBKEY: Pubkey = Pubkey([
223 157, 90, 116, 11, 120, 205, 121, 221, 134, 130, 113, 18, 9, 209, 179, 246, 37, 95, 224, 226,
224 236, 170, 222, 25, 251, 236, 215, 228, 124, 135, 135, 107,
225]);