1use super::{create_mint, create_token_account, ExternalPrice, Metadata};
2use mpl_token_vault::{instruction, state::PREFIX};
3use solana_program::{pubkey::Pubkey, system_instruction};
4use solana_program_test::*;
5use solana_sdk::{
6 signature::{Keypair, Signer},
7 transaction::Transaction,
8 transport,
9};
10
11pub struct Vault {
12 pub keypair: Keypair,
13 pub mint: Keypair,
14 pub redeem_treasury: Keypair,
15 pub fraction_treasury: Keypair,
16}
17
18impl Default for Vault {
19 fn default() -> Self {
20 Self::new()
21 }
22}
23
24impl Vault {
25 pub fn new() -> Self {
26 Vault {
27 keypair: Keypair::new(),
28 mint: Keypair::new(),
29 redeem_treasury: Keypair::new(),
30 fraction_treasury: Keypair::new(),
31 }
32 }
33
34 pub async fn add_token_to_inactive_vault(
35 &self,
36 context: &mut ProgramTestContext,
37 amount: u64,
38 metadata: &Metadata,
39 ) -> transport::Result<(Pubkey, Pubkey)> {
40 let vault_pubkey = self.keypair.pubkey();
41 let metaplex_token_vault_id = mpl_token_vault::id();
42
43 let store = Keypair::new();
44 let token_mint_pubkey = metadata.mint.pubkey();
45
46 let seeds = &[
47 PREFIX.as_bytes(),
48 vault_pubkey.as_ref(),
49 token_mint_pubkey.as_ref(),
50 ];
51 let (safety_deposit_box, _) = Pubkey::find_program_address(seeds, &metaplex_token_vault_id);
52 let seeds = &[
53 PREFIX.as_bytes(),
54 metaplex_token_vault_id.as_ref(),
55 vault_pubkey.as_ref(),
56 ];
57 let (authority, _) = Pubkey::find_program_address(seeds, &metaplex_token_vault_id);
58 create_token_account(context, &store, &token_mint_pubkey, &authority).await?;
59
60 let tx = Transaction::new_signed_with_payer(
61 &[instruction::create_add_token_to_inactive_vault_instruction(
62 mpl_token_vault::id(),
63 safety_deposit_box,
64 metadata.token.pubkey(),
65 store.pubkey(),
66 self.keypair.pubkey(),
67 context.payer.pubkey(),
68 context.payer.pubkey(),
69 context.payer.pubkey(),
70 amount,
71 )],
72 Some(&context.payer.pubkey()),
73 &[&context.payer, &context.payer, &context.payer],
74 context.last_blockhash,
75 );
76 context.banks_client.process_transaction(tx).await?;
77
78 Ok((safety_deposit_box, store.pubkey()))
79 }
80
81 pub async fn activate(
82 &self,
83 context: &mut ProgramTestContext,
84 number_of_shares: u64,
85 ) -> Result<(), BanksClientError> {
86 let metaplex_token_vault_id = mpl_token_vault::id();
87 let vault_pubkey = self.keypair.pubkey();
88
89 let seeds = &[
90 PREFIX.as_bytes(),
91 metaplex_token_vault_id.as_ref(),
92 vault_pubkey.as_ref(),
93 ];
94 let (authority, _) = Pubkey::find_program_address(seeds, &metaplex_token_vault_id);
95
96 let tx = Transaction::new_signed_with_payer(
97 &[instruction::create_activate_vault_instruction(
98 mpl_token_vault::id(),
99 self.keypair.pubkey(),
100 self.mint.pubkey(),
101 self.fraction_treasury.pubkey(),
102 authority,
103 context.payer.pubkey(),
104 number_of_shares,
105 )],
106 Some(&context.payer.pubkey()),
107 &[&context.payer],
108 context.last_blockhash,
109 );
110
111 context.banks_client.process_transaction(tx).await
112 }
113
114 pub async fn combine(
115 &self,
116 context: &mut ProgramTestContext,
117 external_price: &ExternalPrice,
118 ) -> Result<(), BanksClientError> {
119 let outstanding_token_account = Keypair::new();
120 let paying_token_account = Keypair::new();
121
122 let metaplex_token_vault_id = mpl_token_vault::id();
123 let vault_pubkey = self.keypair.pubkey();
124
125 create_token_account(
126 context,
127 &outstanding_token_account,
128 &self.mint.pubkey(),
129 &context.payer.pubkey(),
130 )
131 .await?;
132 create_token_account(
133 context,
134 &paying_token_account,
135 &external_price.price_mint.pubkey(),
136 &context.payer.pubkey(),
137 )
138 .await?;
139
140 let seeds = &[
141 PREFIX.as_bytes(),
142 metaplex_token_vault_id.as_ref(),
143 vault_pubkey.as_ref(),
144 ];
145 let (authority, _) = Pubkey::find_program_address(seeds, &metaplex_token_vault_id);
146
147 let tx = Transaction::new_signed_with_payer(
148 &[instruction::create_combine_vault_instruction(
149 mpl_token_vault::id(),
150 self.keypair.pubkey(),
151 outstanding_token_account.pubkey(),
152 paying_token_account.pubkey(),
153 self.mint.pubkey(),
154 self.fraction_treasury.pubkey(),
155 self.redeem_treasury.pubkey(),
156 context.payer.pubkey(),
157 context.payer.pubkey(),
158 context.payer.pubkey(),
159 authority,
160 external_price.keypair.pubkey(),
161 )],
162 Some(&context.payer.pubkey()),
163 &[&context.payer, &context.payer, &context.payer],
164 context.last_blockhash,
165 );
166
167 context.banks_client.process_transaction(tx).await
168 }
169
170 pub async fn create(
171 &self,
172 context: &mut ProgramTestContext,
173 external_price: &ExternalPrice,
174 ) -> Result<(), BanksClientError> {
175 let metaplex_token_vault_id = mpl_token_vault::id();
176 let vault_pubkey = self.keypair.pubkey();
177
178 let seeds = &[
179 PREFIX.as_bytes(),
180 metaplex_token_vault_id.as_ref(),
181 vault_pubkey.as_ref(),
182 ];
183 let (authority, _) = Pubkey::find_program_address(seeds, &metaplex_token_vault_id);
184
185 create_mint(context, &self.mint, &authority, Some(&authority)).await?;
186 create_token_account(
187 context,
188 &self.redeem_treasury,
189 &external_price.price_mint.pubkey(),
190 &authority,
191 )
192 .await?;
193 create_token_account(
194 context,
195 &self.fraction_treasury,
196 &self.mint.pubkey(),
197 &authority,
198 )
199 .await?;
200
201 let rent = context.banks_client.get_rent().await.unwrap();
202 let tx = Transaction::new_signed_with_payer(
203 &[
204 system_instruction::create_account(
205 &context.payer.pubkey(),
206 &self.keypair.pubkey(),
207 rent.minimum_balance(mpl_token_vault::state::MAX_VAULT_SIZE),
208 mpl_token_vault::state::MAX_VAULT_SIZE as u64,
209 &mpl_token_vault::id(),
210 ),
211 instruction::create_init_vault_instruction(
212 mpl_token_vault::id(),
213 self.mint.pubkey(),
214 self.redeem_treasury.pubkey(),
215 self.fraction_treasury.pubkey(),
216 self.keypair.pubkey(),
217 context.payer.pubkey(),
218 external_price.keypair.pubkey(),
219 false,
220 ),
221 ],
222 Some(&context.payer.pubkey()),
223 &[&context.payer, &context.payer, &self.keypair],
224 context.last_blockhash,
225 );
226
227 context.banks_client.process_transaction(tx).await
228 }
229}