anchor_litesvm/
program.rs1use anchor_lang::{InstructionData, ToAccountMetas};
7use solana_program::{instruction::Instruction, pubkey::Pubkey};
8
9#[derive(Copy, Clone)]
19pub struct Program {
20 program_id: Pubkey,
21}
22
23impl Program {
24 pub fn new(program_id: Pubkey) -> Self {
26 Self { program_id }
27 }
28
29 pub fn accounts<T: ToAccountMetas>(self, accounts: T) -> InstructionBuilder {
45 InstructionBuilder {
46 program_id: self.program_id,
47 accounts: accounts.to_account_metas(None),
48 data: Vec::new(),
49 }
50 }
51
52 pub fn id(&self) -> Pubkey {
54 self.program_id
55 }
56}
57
58pub struct InstructionBuilder {
62 program_id: Pubkey,
63 accounts: Vec<solana_program::instruction::AccountMeta>,
64 data: Vec<u8>,
65}
66
67impl InstructionBuilder {
68 pub fn args<T: InstructionData>(mut self, args: T) -> Self {
75 self.data = args.data();
76 self
77 }
78
79 pub fn instruction(self) -> Result<Instruction, Box<dyn std::error::Error>> {
91 if self.data.is_empty() {
92 return Err("No instruction data provided. Call .args() before .instruction()".into());
93 }
94
95 Ok(Instruction {
96 program_id: self.program_id,
97 accounts: self.accounts,
98 data: self.data,
99 })
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::Program;
106 use anchor_lang::{prelude::*, InstructionData, ToAccountMetas};
107 use solana_program::instruction::AccountMeta;
108 use solana_program::pubkey::Pubkey;
109
110 struct TestAccounts {
111 user: Pubkey,
112 account: Pubkey,
113 }
114
115 impl ToAccountMetas for TestAccounts {
116 fn to_account_metas(&self, _is_signer: Option<bool>) -> Vec<AccountMeta> {
117 vec![
118 AccountMeta::new(self.user, true),
119 AccountMeta::new(self.account, false),
120 ]
121 }
122 }
123
124 #[derive(AnchorSerialize, AnchorDeserialize)]
125 struct TestArgs {
126 amount: u64,
127 }
128
129 impl anchor_lang::Discriminator for TestArgs {
130 const DISCRIMINATOR: &'static [u8] = &[1, 2, 3, 4, 5, 6, 7, 8];
131 }
132
133 impl InstructionData for TestArgs {
134 fn data(&self) -> Vec<u8> {
135 let mut data = Vec::new();
136 data.extend_from_slice(Self::DISCRIMINATOR);
137 self.serialize(&mut data).unwrap();
138 data
139 }
140 }
141
142 #[test]
143 fn test_simplified_syntax() {
144 let program_id = Pubkey::new_unique();
145 let user = Pubkey::new_unique();
146 let account = Pubkey::new_unique();
147
148 let program = Program::new(program_id);
150 let ix = program
151 .accounts(TestAccounts { user, account })
152 .args(TestArgs { amount: 100 })
153 .instruction()
154 .unwrap();
155
156 assert_eq!(ix.program_id, program_id);
157 assert_eq!(ix.accounts.len(), 2);
158 assert!(ix.data.len() > 8);
159 }
160}