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