1pub mod args;
2
3pub use args::*;
4
5use wincode::{config::DefaultConfig, SchemaRead, SchemaWrite};
6
7pub trait InstructionArgs: SchemaWrite<DefaultConfig, Src = Self> {
8 const TAG: u8;
9}
10
11pub mod tags {
12 pub const INITIALIZE_PROGRAM: u8 = 0;
13 pub const INITIALIZE_VAULT: u8 = 1;
14 pub const AUTHORIZE_ACTION: u8 = 2;
15 pub const REVOKE_ACTION: u8 = 3;
16 pub const MANAGE: u8 = 4;
17 pub const MANAGE_BATCH: u8 = 5;
18 pub const REPORT_NAV: u8 = 6;
19 pub const DEPOSIT: u8 = 7;
20 pub const REDEEM: u8 = 8;
21 pub const CANCEL_REDEEM: u8 = 9;
22 pub const PROCESS_WITHDRAWALS: u8 = 10;
23 pub const UPDATE_VAULT_CONFIG: u8 = 11;
24 pub const INITIALIZE_ASSET: u8 = 12;
25 pub const UPDATE_ASSET: u8 = 13;
26 pub const SET_PAUSE_FLAGS: u8 = 14;
27 pub const SET_VAULT_ACCESS: u8 = 15;
28 pub const TRANSFER_PROGRAM_AUTHORITY: u8 = 16;
29 pub const TRANSFER_VAULT_AUTHORITY: u8 = 17;
30 pub const SET_STRATEGIST: u8 = 18;
31 pub const SET_NAV_AUTHORITY: u8 = 19;
32 pub const SET_WITHDRAWAL_AUTHORITY: u8 = 20;
33 pub const COLLECT_FEES: u8 = 21;
34 pub const INVEST_EXTERNAL: u8 = 22;
35 pub const RETURN_EXTERNAL: u8 = 23;
36 pub const SET_SWAP_AUTHORITY: u8 = 24;
37 pub const ATOMIC_REDEEM: u8 = 25;
38 pub const SWAP: u8 = 26;
39 pub const WRITE_DOWN_FEES: u8 = 27;
40 pub const REGISTER_EXTERNAL_DESTINATION: u8 = 28;
41 pub const REVOKE_EXTERNAL_DESTINATION: u8 = 29;
42 pub const SET_SHARE_METADATA: u8 = 30;
43}
44
45#[repr(u8)]
48#[derive(codama_macros::CodamaInstructions)]
49#[allow(clippy::large_enum_variant)]
50#[codama(program(
51 name = "roshi",
52 address = "Roshi11111111111111111111111111111111111111"
53))]
54pub enum RoshiInstruction {
55 #[codama(account(name = "payer", signer, writable))]
56 #[codama(account(name = "program_config", writable))]
57 #[codama(account(name = "system_program", default_value = program("system")))]
58 InitializeProgram(#[codama(name = "args")] InitializeProgramArgs) = 0,
59
60 #[codama(account(name = "program_authority", signer))]
61 #[codama(account(name = "program_config"))]
62 #[codama(account(name = "payer", signer, writable))]
63 #[codama(account(name = "vault", writable))]
64 #[codama(account(name = "base_mint"))]
65 #[codama(account(name = "share_mint", writable))]
66 #[codama(account(name = "treasury"))]
67 #[codama(account(name = "system_program", default_value = program("system")))]
68 #[codama(account(name = "token_program", default_value = program("token")))]
69 InitializeVault(#[codama(name = "args")] InitializeVaultArgs) = 1,
70
71 #[codama(account(name = "admin", signer, writable))]
72 #[codama(account(name = "vault"))]
73 #[codama(account(name = "action", writable))]
74 #[codama(account(name = "system_program", default_value = program("system")))]
75 AuthorizeAction(#[codama(name = "args")] AuthorizeActionArgs) = 2,
76
77 #[codama(account(name = "admin", signer))]
78 #[codama(account(name = "vault"))]
79 #[codama(account(name = "action", writable))]
80 RevokeAction(#[codama(name = "args")] RevokeActionArgs) = 3,
81
82 #[codama(account(name = "executor", signer))]
83 #[codama(account(name = "vault"))]
84 #[codama(account(name = "sub_account", writable))]
85 #[codama(account(name = "action"))]
86 Manage(#[codama(name = "args")] ManageArgs) = 4,
87
88 #[codama(account(name = "executor", signer))]
89 #[codama(account(name = "vault"))]
90 ManageBatch(#[codama(name = "args")] ManageBatchArgs) = 5,
91
92 #[codama(account(name = "nav_authority", signer))]
93 #[codama(account(name = "vault", writable))]
94 #[codama(account(name = "share_mint"))]
95 #[codama(account(name = "base_mint"))]
96 #[codama(account(name = "deposit_base_custody"))]
97 #[codama(account(name = "withdraw_base_custody"))]
98 ReportNav(#[codama(name = "args")] ReportNavArgs) = 6,
99
100 #[codama(account(name = "depositor", signer))]
101 #[codama(account(name = "vault", writable))]
102 #[codama(account(name = "user_source_token_account", writable))]
103 #[codama(account(name = "vault_custody_token_account", writable))]
104 #[codama(account(name = "user_share_account", writable))]
105 #[codama(account(name = "share_mint", writable))]
106 #[codama(account(name = "share_token_program", default_value = program("token")))]
107 #[codama(account(name = "asset_token_program"))]
108 Deposit(#[codama(name = "args")] DepositArgs) = 7,
109
110 #[codama(account(name = "owner", signer, writable))]
111 #[codama(account(name = "vault", writable))]
112 #[codama(account(name = "user_share_account", writable))]
113 #[codama(account(name = "share_mint", writable))]
114 #[codama(account(name = "recipient_token_account"))]
115 #[codama(account(name = "withdrawal_ticket", writable))]
116 #[codama(account(name = "system_program", default_value = program("system")))]
117 #[codama(account(name = "token_program", default_value = program("token")))]
118 Redeem(#[codama(name = "args")] RedeemArgs) = 8,
119
120 #[codama(account(name = "owner", signer, writable))]
121 #[codama(account(name = "vault", writable))]
122 #[codama(account(name = "withdrawal_ticket", writable))]
123 #[codama(account(name = "share_mint", writable))]
124 #[codama(account(name = "owner_share_account", writable))]
125 #[codama(account(name = "token_program", default_value = program("token")))]
126 CancelRedeem(#[codama(name = "args")] CancelRedeemArgs) = 9,
127
128 #[codama(account(name = "withdrawal_authority", signer))]
129 #[codama(account(name = "vault", writable))]
130 #[codama(account(name = "withdraw_sub_account"))]
131 #[codama(account(name = "custody", writable))]
132 #[codama(account(name = "share_mint"))]
133 #[codama(account(name = "token_program", default_value = program("token")))]
134 ProcessWithdrawals = 10,
135
136 #[codama(account(name = "admin", signer))]
137 #[codama(account(name = "vault", writable))]
138 #[codama(account(name = "treasury"))]
139 UpdateVaultConfig(#[codama(name = "args")] UpdateVaultConfigArgs) = 11,
140
141 #[codama(account(name = "admin", signer, writable))]
142 #[codama(account(name = "vault"))]
143 #[codama(account(name = "asset_mint"))]
144 #[codama(account(name = "asset", writable))]
145 #[codama(account(name = "system_program", default_value = program("system")))]
146 InitializeAsset(#[codama(name = "args")] InitializeAssetArgs) = 12,
147
148 #[codama(account(name = "admin", signer))]
149 #[codama(account(name = "vault"))]
150 #[codama(account(name = "asset", writable))]
151 UpdateAsset(#[codama(name = "args")] UpdateAssetArgs) = 13,
152
153 #[codama(account(name = "admin", signer))]
154 #[codama(account(name = "vault", writable))]
155 SetPauseFlags(#[codama(name = "args")] SetPauseFlagsArgs) = 14,
156
157 #[codama(account(name = "admin", signer))]
158 #[codama(account(name = "vault", writable))]
159 SetVaultAccess(#[codama(name = "args")] SetVaultAccessArgs) = 15,
160
161 #[codama(account(name = "authority", signer))]
162 #[codama(account(name = "program_config", writable))]
163 TransferProgramAuthority(#[codama(name = "args")] TransferProgramAuthorityArgs) = 16,
164
165 #[codama(account(name = "admin", signer))]
166 #[codama(account(name = "vault", writable))]
167 TransferVaultAuthority(#[codama(name = "args")] TransferVaultAuthorityArgs) = 17,
168
169 #[codama(account(name = "admin", signer))]
170 #[codama(account(name = "vault", writable))]
171 SetStrategist(#[codama(name = "args")] SetStrategistArgs) = 18,
172
173 #[codama(account(name = "admin", signer))]
174 #[codama(account(name = "vault", writable))]
175 SetNavAuthority(#[codama(name = "args")] SetNavAuthorityArgs) = 19,
176
177 #[codama(account(name = "admin", signer))]
178 #[codama(account(name = "vault", writable))]
179 SetWithdrawalAuthority(#[codama(name = "args")] SetWithdrawalAuthorityArgs) = 20,
180
181 #[codama(account(name = "admin", signer))]
182 #[codama(account(name = "vault", writable))]
183 #[codama(account(name = "fee_sub_account"))]
184 #[codama(account(name = "custody", writable))]
185 #[codama(account(name = "treasury", writable))]
186 #[codama(account(name = "token_program", default_value = program("token")))]
187 CollectFees(#[codama(name = "args")] CollectFeesArgs) = 21,
188
189 #[codama(account(name = "strategist", signer))]
190 #[codama(account(name = "vault", writable))]
191 #[codama(account(name = "sub_account"))]
192 #[codama(account(name = "custody", writable))]
193 #[codama(account(name = "external_account", writable))]
194 #[codama(account(name = "external_destination"))]
195 #[codama(account(name = "token_program", default_value = program("token")))]
196 InvestExternal(#[codama(name = "args")] InvestExternalArgs) = 22,
197
198 #[codama(account(name = "strategist", signer))]
199 #[codama(account(name = "external_authority", signer))]
200 #[codama(account(name = "vault", writable))]
201 #[codama(account(name = "sub_account"))]
202 #[codama(account(name = "external_account", writable))]
203 #[codama(account(name = "custody", writable))]
204 #[codama(account(name = "token_program", default_value = program("token")))]
205 ReturnExternal(#[codama(name = "args")] ReturnExternalArgs) = 23,
206
207 #[codama(account(name = "admin", signer))]
208 #[codama(account(name = "vault", writable))]
209 SetSwapAuthority(#[codama(name = "args")] SetSwapAuthorityArgs) = 24,
210
211 #[codama(account(name = "owner", signer, writable))]
212 #[codama(account(name = "vault", writable))]
213 #[codama(account(name = "user_share_account", writable))]
214 #[codama(account(name = "share_mint", writable))]
215 #[codama(account(name = "recipient_token_account", writable))]
216 #[codama(account(name = "custody", writable))]
217 #[codama(account(name = "base_token_program"))]
218 #[codama(account(name = "sub_account"))]
219 #[codama(account(name = "action"))]
220 #[codama(account(name = "token_program", default_value = program("token")))]
221 AtomicRedeem(#[codama(name = "args")] AtomicRedeemArgs) = 25,
222
223 #[codama(account(name = "swap_authority", signer))]
224 #[codama(account(name = "vault"))]
225 #[codama(account(name = "sub_account"))]
226 #[codama(account(name = "input_custody", writable))]
227 #[codama(account(name = "output_custody", writable))]
228 #[codama(account(name = "action"))]
229 Swap(#[codama(name = "args")] SwapArgs) = 26,
230
231 #[codama(account(name = "admin", signer))]
232 #[codama(account(name = "vault", writable))]
233 WriteDownFees(#[codama(name = "args")] WriteDownFeesArgs) = 27,
234
235 #[codama(account(name = "admin", signer, writable))]
236 #[codama(account(name = "vault"))]
237 #[codama(account(name = "destination_token_account"))]
238 #[codama(account(name = "external_destination", writable))]
239 #[codama(account(name = "system_program", default_value = program("system")))]
240 RegisterExternalDestination = 28,
241
242 #[codama(account(name = "admin", signer, writable))]
243 #[codama(account(name = "vault"))]
244 #[codama(account(name = "external_destination", writable))]
245 RevokeExternalDestination = 29,
246
247 #[codama(account(name = "admin", signer, writable))]
248 #[codama(account(name = "vault"))]
249 #[codama(account(name = "share_mint"))]
250 #[codama(account(name = "metadata", writable))]
251 #[codama(account(name = "token_metadata_program"))]
252 #[codama(account(name = "system_program", default_value = program("system")))]
253 SetShareMetadata(#[codama(name = "args")] SetShareMetadataArgs) = 30,
254}
255
256impl RoshiInstruction {
257 pub const fn tag(&self) -> u8 {
258 match self {
259 Self::InitializeProgram(_) => tags::INITIALIZE_PROGRAM,
260 Self::InitializeVault(_) => tags::INITIALIZE_VAULT,
261 Self::AuthorizeAction(_) => tags::AUTHORIZE_ACTION,
262 Self::RevokeAction(_) => tags::REVOKE_ACTION,
263 Self::Manage(_) => tags::MANAGE,
264 Self::ManageBatch(_) => tags::MANAGE_BATCH,
265 Self::ReportNav(_) => tags::REPORT_NAV,
266 Self::Deposit(_) => tags::DEPOSIT,
267 Self::Redeem(_) => tags::REDEEM,
268 Self::CancelRedeem(_) => tags::CANCEL_REDEEM,
269 Self::ProcessWithdrawals => tags::PROCESS_WITHDRAWALS,
270 Self::UpdateVaultConfig(_) => tags::UPDATE_VAULT_CONFIG,
271 Self::InitializeAsset(_) => tags::INITIALIZE_ASSET,
272 Self::UpdateAsset(_) => tags::UPDATE_ASSET,
273 Self::InvestExternal(_) => tags::INVEST_EXTERNAL,
274 Self::ReturnExternal(_) => tags::RETURN_EXTERNAL,
275 Self::SetPauseFlags(_) => tags::SET_PAUSE_FLAGS,
276 Self::SetVaultAccess(_) => tags::SET_VAULT_ACCESS,
277 Self::TransferProgramAuthority(_) => tags::TRANSFER_PROGRAM_AUTHORITY,
278 Self::TransferVaultAuthority(_) => tags::TRANSFER_VAULT_AUTHORITY,
279 Self::SetStrategist(_) => tags::SET_STRATEGIST,
280 Self::SetSwapAuthority(_) => tags::SET_SWAP_AUTHORITY,
281 Self::SetNavAuthority(_) => tags::SET_NAV_AUTHORITY,
282 Self::SetWithdrawalAuthority(_) => tags::SET_WITHDRAWAL_AUTHORITY,
283 Self::CollectFees(_) => tags::COLLECT_FEES,
284 Self::AtomicRedeem(_) => tags::ATOMIC_REDEEM,
285 Self::Swap(_) => tags::SWAP,
286 Self::WriteDownFees(_) => tags::WRITE_DOWN_FEES,
287 Self::RegisterExternalDestination => tags::REGISTER_EXTERNAL_DESTINATION,
288 Self::RevokeExternalDestination => tags::REVOKE_EXTERNAL_DESTINATION,
289 Self::SetShareMetadata(_) => tags::SET_SHARE_METADATA,
290 }
291 }
292
293 #[allow(clippy::result_unit_err)]
294 pub fn decode(data: &[u8]) -> Result<Self, ()> {
295 let (tag, payload) = data.split_first().ok_or(())?;
296
297 match *tag {
298 tags::INITIALIZE_PROGRAM => Ok(Self::InitializeProgram(decode_payload(payload)?)),
299 tags::INITIALIZE_VAULT => Ok(Self::InitializeVault(decode_payload(payload)?)),
300 tags::AUTHORIZE_ACTION => Ok(Self::AuthorizeAction(decode_payload(payload)?)),
301 tags::REVOKE_ACTION => Ok(Self::RevokeAction(decode_payload(payload)?)),
302 tags::MANAGE => Ok(Self::Manage(decode_payload(payload)?)),
303 tags::MANAGE_BATCH => Ok(Self::ManageBatch(decode_payload(payload)?)),
304 tags::REPORT_NAV => Ok(Self::ReportNav(decode_payload(payload)?)),
305 tags::DEPOSIT => Ok(Self::Deposit(decode_payload(payload)?)),
306 tags::REDEEM => Ok(Self::Redeem(decode_payload(payload)?)),
307 tags::CANCEL_REDEEM => Ok(Self::CancelRedeem(decode_payload(payload)?)),
308 tags::PROCESS_WITHDRAWALS => {
309 let ProcessWithdrawalsArgs = decode_payload(payload)?;
310 Ok(Self::ProcessWithdrawals)
311 }
312 tags::UPDATE_VAULT_CONFIG => Ok(Self::UpdateVaultConfig(decode_payload(payload)?)),
313 tags::INITIALIZE_ASSET => Ok(Self::InitializeAsset(decode_payload(payload)?)),
314 tags::UPDATE_ASSET => Ok(Self::UpdateAsset(decode_payload(payload)?)),
315 tags::INVEST_EXTERNAL => Ok(Self::InvestExternal(decode_payload(payload)?)),
316 tags::RETURN_EXTERNAL => Ok(Self::ReturnExternal(decode_payload(payload)?)),
317 tags::SET_PAUSE_FLAGS => Ok(Self::SetPauseFlags(decode_payload(payload)?)),
318 tags::SET_VAULT_ACCESS => Ok(Self::SetVaultAccess(decode_payload(payload)?)),
319 tags::TRANSFER_PROGRAM_AUTHORITY => {
320 Ok(Self::TransferProgramAuthority(decode_payload(payload)?))
321 }
322 tags::TRANSFER_VAULT_AUTHORITY => {
323 Ok(Self::TransferVaultAuthority(decode_payload(payload)?))
324 }
325 tags::SET_STRATEGIST => Ok(Self::SetStrategist(decode_payload(payload)?)),
326 tags::SET_SWAP_AUTHORITY => Ok(Self::SetSwapAuthority(decode_payload(payload)?)),
327 tags::SET_NAV_AUTHORITY => Ok(Self::SetNavAuthority(decode_payload(payload)?)),
328 tags::SET_WITHDRAWAL_AUTHORITY => {
329 Ok(Self::SetWithdrawalAuthority(decode_payload(payload)?))
330 }
331 tags::COLLECT_FEES => Ok(Self::CollectFees(decode_payload(payload)?)),
332 tags::ATOMIC_REDEEM => Ok(Self::AtomicRedeem(decode_payload(payload)?)),
333 tags::SWAP => Ok(Self::Swap(decode_payload(payload)?)),
334 tags::WRITE_DOWN_FEES => Ok(Self::WriteDownFees(decode_payload(payload)?)),
335 tags::REGISTER_EXTERNAL_DESTINATION => {
336 let RegisterExternalDestinationArgs = decode_payload(payload)?;
337 Ok(Self::RegisterExternalDestination)
338 }
339 tags::REVOKE_EXTERNAL_DESTINATION => {
340 let RevokeExternalDestinationArgs = decode_payload(payload)?;
341 Ok(Self::RevokeExternalDestination)
342 }
343 tags::SET_SHARE_METADATA => Ok(Self::SetShareMetadata(decode_payload(payload)?)),
344 _ => Err(()),
345 }
346 }
347
348 pub fn serialize(&self) -> Result<Vec<u8>, wincode::WriteError> {
349 let mut data = vec![self.tag()];
350
351 match self {
352 Self::InitializeProgram(args) => wincode::serialize_into(&mut data, args)?,
353 Self::InitializeVault(args) => wincode::serialize_into(&mut data, args)?,
354 Self::AuthorizeAction(args) => wincode::serialize_into(&mut data, args)?,
355 Self::RevokeAction(args) => wincode::serialize_into(&mut data, args)?,
356 Self::Manage(args) => wincode::serialize_into(&mut data, args)?,
357 Self::ManageBatch(args) => wincode::serialize_into(&mut data, args)?,
358 Self::ReportNav(args) => wincode::serialize_into(&mut data, args)?,
359 Self::Deposit(args) => wincode::serialize_into(&mut data, args)?,
360 Self::Redeem(args) => wincode::serialize_into(&mut data, args)?,
361 Self::CancelRedeem(args) => wincode::serialize_into(&mut data, args)?,
362 Self::ProcessWithdrawals => {
363 wincode::serialize_into(&mut data, &ProcessWithdrawalsArgs)?
364 }
365 Self::UpdateVaultConfig(args) => wincode::serialize_into(&mut data, args)?,
366 Self::InitializeAsset(args) => wincode::serialize_into(&mut data, args)?,
367 Self::UpdateAsset(args) => wincode::serialize_into(&mut data, args)?,
368 Self::InvestExternal(args) => wincode::serialize_into(&mut data, args)?,
369 Self::ReturnExternal(args) => wincode::serialize_into(&mut data, args)?,
370 Self::SetPauseFlags(args) => wincode::serialize_into(&mut data, args)?,
371 Self::SetVaultAccess(args) => wincode::serialize_into(&mut data, args)?,
372 Self::TransferProgramAuthority(args) => wincode::serialize_into(&mut data, args)?,
373 Self::TransferVaultAuthority(args) => wincode::serialize_into(&mut data, args)?,
374 Self::SetStrategist(args) => wincode::serialize_into(&mut data, args)?,
375 Self::SetSwapAuthority(args) => wincode::serialize_into(&mut data, args)?,
376 Self::SetNavAuthority(args) => wincode::serialize_into(&mut data, args)?,
377 Self::SetWithdrawalAuthority(args) => wincode::serialize_into(&mut data, args)?,
378 Self::CollectFees(args) => wincode::serialize_into(&mut data, args)?,
379 Self::AtomicRedeem(args) => wincode::serialize_into(&mut data, args)?,
380 Self::Swap(args) => wincode::serialize_into(&mut data, args)?,
381 Self::WriteDownFees(args) => wincode::serialize_into(&mut data, args)?,
382 Self::RegisterExternalDestination => {
383 wincode::serialize_into(&mut data, &RegisterExternalDestinationArgs)?
384 }
385 Self::RevokeExternalDestination => {
386 wincode::serialize_into(&mut data, &RevokeExternalDestinationArgs)?
387 }
388 Self::SetShareMetadata(args) => wincode::serialize_into(&mut data, args)?,
389 }
390
391 Ok(data)
392 }
393}
394
395fn decode_payload<'a, T>(payload: &'a [u8]) -> Result<T, ()>
396where
397 T: SchemaRead<'a, DefaultConfig, Dst = T>,
398{
399 wincode::deserialize_exact(payload).map_err(|_| ())
400}
401
402macro_rules! impl_instruction_args {
403 ($( $args:ty = $tag:expr ),+ $(,)?) => {
404 $(
405 impl InstructionArgs for $args {
406 const TAG: u8 = $tag;
407 }
408 )+
409
410 #[cfg(test)]
411 const TAG_CASES: &[u8] = &[
412 $(
413 $tag,
414 )+
415 ];
416 };
417}
418
419impl_instruction_args! {
420 InitializeProgramArgs = tags::INITIALIZE_PROGRAM,
421 InitializeVaultArgs = tags::INITIALIZE_VAULT,
422 AuthorizeActionArgs = tags::AUTHORIZE_ACTION,
423 RevokeActionArgs = tags::REVOKE_ACTION,
424 ManageArgs = tags::MANAGE,
425 ManageBatchArgs = tags::MANAGE_BATCH,
426 ReportNavArgs = tags::REPORT_NAV,
427 DepositArgs = tags::DEPOSIT,
428 RedeemArgs = tags::REDEEM,
429 CancelRedeemArgs = tags::CANCEL_REDEEM,
430 ProcessWithdrawalsArgs = tags::PROCESS_WITHDRAWALS,
431 UpdateVaultConfigArgs = tags::UPDATE_VAULT_CONFIG,
432 InitializeAssetArgs = tags::INITIALIZE_ASSET,
433 UpdateAssetArgs = tags::UPDATE_ASSET,
434 SetPauseFlagsArgs = tags::SET_PAUSE_FLAGS,
435 SetVaultAccessArgs = tags::SET_VAULT_ACCESS,
436 TransferProgramAuthorityArgs = tags::TRANSFER_PROGRAM_AUTHORITY,
437 TransferVaultAuthorityArgs = tags::TRANSFER_VAULT_AUTHORITY,
438 SetStrategistArgs = tags::SET_STRATEGIST,
439 SetNavAuthorityArgs = tags::SET_NAV_AUTHORITY,
440 SetWithdrawalAuthorityArgs = tags::SET_WITHDRAWAL_AUTHORITY,
441 CollectFeesArgs = tags::COLLECT_FEES,
442 InvestExternalArgs = tags::INVEST_EXTERNAL,
443 ReturnExternalArgs = tags::RETURN_EXTERNAL,
444 SetSwapAuthorityArgs = tags::SET_SWAP_AUTHORITY,
445 AtomicRedeemArgs = tags::ATOMIC_REDEEM,
446 SwapArgs = tags::SWAP,
447 WriteDownFeesArgs = tags::WRITE_DOWN_FEES,
448 RegisterExternalDestinationArgs = tags::REGISTER_EXTERNAL_DESTINATION,
449 RevokeExternalDestinationArgs = tags::REVOKE_EXTERNAL_DESTINATION,
450 SetShareMetadataArgs = tags::SET_SHARE_METADATA,
451}
452
453pub fn serialize_instruction<T>(args: &T) -> Result<Vec<u8>, wincode::WriteError>
454where
455 T: InstructionArgs,
456{
457 let mut data = vec![T::TAG];
458 wincode::serialize_into(&mut data, args)?;
459 Ok(data)
460}
461
462#[cfg(test)]
463mod tests {
464 use super::*;
465 use codama::{Codama, NodeTrait};
466 use serde_json::Value;
467 use std::path::Path;
468 use wincode::deserialize_exact;
469
470 #[test]
471 fn instruction_args_tags_match_canonical_tags() {
472 assert_eq!(
473 TAG_CASES,
474 &[
475 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
476 23, 24, 25, 26, 27, 28, 29, 30
477 ]
478 );
479 assert_eq!(
480 RoshiInstruction::ProcessWithdrawals.tag(),
481 <ProcessWithdrawalsArgs as InstructionArgs>::TAG
482 );
483 }
484
485 #[test]
486 fn codama_idl_uses_canonical_instruction_discriminators() {
487 let mut idl = Codama::load(Path::new(env!("CARGO_MANIFEST_DIR")))
488 .unwrap()
489 .get_idl()
490 .unwrap();
491 idl.program.name = "roshi".into();
492 let idl: Value = serde_json::from_str(&idl.to_json().unwrap()).unwrap();
493 let instructions = idl["program"]["instructions"].as_array().unwrap();
494
495 assert_eq!(idl["program"]["name"], "roshi");
496 assert_eq!(
497 idl["program"]["publicKey"],
498 "Roshi11111111111111111111111111111111111111"
499 );
500 assert_eq!(instructions.len(), TAG_CASES.len());
501
502 for (name, tag) in IDL_TAG_CASES {
503 assert_instruction_discriminator(instructions, name, *tag);
504 }
505
506 let deposit = instruction(instructions, "deposit");
507 assert_eq!(deposit["arguments"][1]["name"], "args");
508 assert_eq!(deposit["arguments"][1]["type"]["name"], "depositArgs");
509
510 let process_withdrawals = instruction(instructions, "processWithdrawals");
511 assert_eq!(
512 process_withdrawals["arguments"].as_array().unwrap().len(),
513 1
514 );
515 }
516
517 #[test]
518 fn instruction_decode_rejects_unknown_values() {
519 assert!(RoshiInstruction::decode(&[255]).is_err());
520 }
521
522 #[test]
523 fn serialize_instruction_writes_tag_then_args_payload() {
524 let args = DepositArgs {
525 asset_mint: [4; 32],
526 amount: 123,
527 min_shares_out: 456,
528 access_proof: vec![[1; 32], [2; 32], [3; 32]],
529 };
530
531 let encoded = serialize_instruction(&args).unwrap();
532 let decoded: DepositArgs = deserialize_exact(&encoded[1..]).unwrap();
533
534 assert_eq!(encoded[0], <DepositArgs as InstructionArgs>::TAG);
535 assert_eq!(decoded.asset_mint, [4; 32]);
536 assert_eq!(decoded.amount, 123);
537 assert_eq!(decoded.min_shares_out, 456);
538 assert_eq!(decoded.access_proof, vec![[1; 32], [2; 32], [3; 32]]);
539 }
540
541 #[test]
542 fn canonical_instruction_serializes_like_args_helper() {
543 let args = DepositArgs {
544 asset_mint: [4; 32],
545 amount: 123,
546 min_shares_out: 456,
547 access_proof: vec![[1; 32]],
548 };
549
550 assert_eq!(
551 RoshiInstruction::Deposit(args).serialize().unwrap(),
552 serialize_instruction(&DepositArgs {
553 asset_mint: [4; 32],
554 amount: 123,
555 min_shares_out: 456,
556 access_proof: vec![[1; 32]],
557 })
558 .unwrap()
559 );
560 }
561
562 #[test]
563 fn serialize_zero_sized_args_writes_only_tag() {
564 assert_eq!(
565 serialize_instruction(&ProcessWithdrawalsArgs).unwrap(),
566 vec![<ProcessWithdrawalsArgs as InstructionArgs>::TAG]
567 );
568 assert_eq!(
569 RoshiInstruction::ProcessWithdrawals.serialize().unwrap(),
570 vec![<ProcessWithdrawalsArgs as InstructionArgs>::TAG]
571 );
572 }
573
574 fn instruction<'a>(instructions: &'a [Value], name: &str) -> &'a Value {
575 instructions
576 .iter()
577 .find(|instruction| instruction["name"] == name)
578 .unwrap()
579 }
580
581 fn assert_instruction_discriminator(instructions: &[Value], name: &str, tag: u8) {
582 assert_eq!(
583 instruction(instructions, name)["arguments"][0]["defaultValue"]["number"],
584 u64::from(tag)
585 );
586 }
587
588 const IDL_TAG_CASES: &[(&str, u8)] = &[
589 ("initializeProgram", tags::INITIALIZE_PROGRAM),
590 ("initializeVault", tags::INITIALIZE_VAULT),
591 ("authorizeAction", tags::AUTHORIZE_ACTION),
592 ("revokeAction", tags::REVOKE_ACTION),
593 ("manage", tags::MANAGE),
594 ("manageBatch", tags::MANAGE_BATCH),
595 ("reportNav", tags::REPORT_NAV),
596 ("deposit", tags::DEPOSIT),
597 ("redeem", tags::REDEEM),
598 ("cancelRedeem", tags::CANCEL_REDEEM),
599 ("processWithdrawals", tags::PROCESS_WITHDRAWALS),
600 ("updateVaultConfig", tags::UPDATE_VAULT_CONFIG),
601 ("initializeAsset", tags::INITIALIZE_ASSET),
602 ("updateAsset", tags::UPDATE_ASSET),
603 ("setPauseFlags", tags::SET_PAUSE_FLAGS),
604 ("setVaultAccess", tags::SET_VAULT_ACCESS),
605 ("transferProgramAuthority", tags::TRANSFER_PROGRAM_AUTHORITY),
606 ("transferVaultAuthority", tags::TRANSFER_VAULT_AUTHORITY),
607 ("setStrategist", tags::SET_STRATEGIST),
608 ("setNavAuthority", tags::SET_NAV_AUTHORITY),
609 ("setWithdrawalAuthority", tags::SET_WITHDRAWAL_AUTHORITY),
610 ("collectFees", tags::COLLECT_FEES),
611 ("investExternal", tags::INVEST_EXTERNAL),
612 ("returnExternal", tags::RETURN_EXTERNAL),
613 ("setSwapAuthority", tags::SET_SWAP_AUTHORITY),
614 ("atomicRedeem", tags::ATOMIC_REDEEM),
615 ("swap", tags::SWAP),
616 ("writeDownFees", tags::WRITE_DOWN_FEES),
617 (
618 "registerExternalDestination",
619 tags::REGISTER_EXTERNAL_DESTINATION,
620 ),
621 (
622 "revokeExternalDestination",
623 tags::REVOKE_EXTERNAL_DESTINATION,
624 ),
625 ("setShareMetadata", tags::SET_SHARE_METADATA),
626 ];
627}