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