spl_token_vault/
instruction.rs

1use {
2    crate::state::{ExternalPriceAccount, Key},
3    borsh::{BorshDeserialize, BorshSerialize},
4    solana_program::{
5        instruction::{AccountMeta, Instruction},
6        pubkey::Pubkey,
7        sysvar,
8    },
9};
10
11#[repr(C)]
12#[derive(BorshSerialize, BorshDeserialize, Clone)]
13pub struct InitVaultArgs {
14    pub allow_further_share_creation: bool,
15}
16
17#[repr(C)]
18#[derive(BorshSerialize, BorshDeserialize, Clone)]
19pub struct AmountArgs {
20    pub amount: u64,
21}
22
23#[repr(C)]
24#[derive(BorshSerialize, BorshDeserialize, Clone)]
25pub struct NumberOfShareArgs {
26    pub number_of_shares: u64,
27}
28
29#[repr(C)]
30#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
31pub struct MintEditionProxyArgs {
32    pub edition: u64,
33}
34
35/// Instructions supported by the Fraction program.
36#[derive(BorshSerialize, BorshDeserialize, Clone)]
37pub enum VaultInstruction {
38    /// Initialize a token vault, starts inactivate. Add tokens in subsequent instructions, then activate.
39    ///   0. `[writable]` Initialized fractional share mint with 0 tokens in supply, authority on mint must be pda of program with seed [prefix, programid]
40    ///   1. `[writable]` Initialized redeem treasury token account with 0 tokens in supply, owner of account must be pda of program like above
41    ///   2. `[writable]` Initialized fraction treasury token account with 0 tokens in supply, owner of account must be pda of program like above
42    ///   3. `[writable]` Uninitialized vault account
43    ///   4. `[]` Authority on the vault
44    ///   5. `[]` Pricing Lookup Address
45    ///   6. `[]` Token program
46    ///   7. `[]` Rent sysvar
47    InitVault(InitVaultArgs),
48
49    /// Add a token to a inactive token vault
50    ///   0. `[writable]` Uninitialized safety deposit box account address (will be created and allocated by this endpoint)
51    ///                   Address should be pda with seed of [PREFIX, vault_address, token_mint_address]
52    ///   1. `[writable]` Initialized Token account
53    ///   2. `[writable]` Initialized Token store account with authority of this program, this will get set on the safety deposit box
54    ///   3. `[writable]` Initialized inactive fractionalized token vault
55    ///   4. `[signer]` Authority on the vault
56    ///   5. `[signer]` Payer
57    ///   6. `[signer]` Transfer Authority to move desired token amount from token account to safety deposit
58    ///   7. `[]` Token program
59    ///   8. `[]` Rent sysvar
60    ///   9. `[]` System account sysvar
61    AddTokenToInactiveVault(AmountArgs),
62
63    /// Activates the vault, distributing initial shares into the fraction treasury.
64    /// Tokens can no longer be removed in this state until Combination.
65    ///   0. `[writable]` Initialized inactivated fractionalized token vault
66    ///   1. `[writable]` Fraction mint
67    ///   2. `[writable]` Fraction treasury
68    ///   3. `[]` Fraction mint authority for the program - seed of [PREFIX, program_id]
69    ///   4. `[signer]` Authority on the vault
70    ///   5. `[]` Token program
71    ActivateVault(NumberOfShareArgs),
72
73    /// This act checks the external pricing oracle for permission to combine and the price of the circulating market cap to do so.
74    /// If you can afford it, this amount is charged and placed into the redeem treasury for shareholders to redeem at a later time.
75    /// The treasury then unlocks into Combine state and you can remove the tokens.
76    ///   0. `[writable]` Initialized activated token vault
77    ///   1. `[writable]` Token account containing your portion of the outstanding fraction shares
78    ///   2. `[writable]` Token account of the redeem_treasury mint type that you will pay with
79    ///   3. `[writable]` Fraction mint
80    ///   4. `[writable]` Fraction treasury account
81    ///   5. `[writable]` Redeem treasury account
82    ///   6. `[]` New authority on the vault going forward - can be same authority if you want
83    ///   7. `[signer]` Authority on the vault
84    ///   8. `[signer]` Transfer authority for the token account and outstanding fractional shares account you're transferring from
85    ///   9. `[]` PDA-based Burn authority for the fraction treasury account containing the uncirculated shares seed [PREFIX, program_id]
86    ///   10. `[]` External pricing lookup address
87    ///   11. `[]` Token program
88    CombineVault,
89
90    /// If in the combine state, shareholders can hit this endpoint to burn shares in exchange for monies from the treasury.
91    /// Once fractional supply is zero and all tokens have been removed this action will take vault to Deactivated
92    ///   0. `[writable]` Initialized Token account containing your fractional shares
93    ///   1. `[writable]` Initialized Destination token account where you wish your proceeds to arrive
94    ///   2. `[writable]` Fraction mint
95    ///   3. `[writable]` Redeem treasury account
96    ///   4. `[]` PDA-based Transfer authority for the transfer of proceeds from redeem treasury to destination seed [PREFIX, program_id]
97    ///   5. `[signer]` Burn authority for the burning of your shares
98    ///   6. `[]` Combined token vault
99    ///   7. `[]` Token program
100    ///   8. `[]` Rent sysvar
101    RedeemShares,
102
103    /// If in combine state, authority on vault can hit this to withdrawal some of a token type from a safety deposit box.
104    /// Once fractional supply is zero and all tokens have been removed this action will take vault to Deactivated
105    ///   0. `[writable]` Initialized Destination account for the tokens being withdrawn
106    ///   1. `[writable]` The safety deposit box account key for the tokens
107    ///   2. `[writable]` The store key on the safety deposit box account
108    ///   3. `[writable]` The initialized combined token vault
109    ///   4. `[]` Fraction mint
110    ///   5. `[signer]` Authority of vault
111    ///   6. `[]` PDA-based Transfer authority to move the tokens from the store to the destination seed [PREFIX, program_id]
112    ///   7. `[]` Token program
113    ///   8. `[]` Rent sysvar
114    WithdrawTokenFromSafetyDepositBox(AmountArgs),
115
116    /// Self explanatory - mint more fractional shares if the vault is configured to allow such.
117    ///   0. `[writable]` Fraction treasury
118    ///   1. `[writable]` Fraction mint
119    ///   2. `[]` The initialized active token vault
120    ///   3. `[]` PDA-based Mint authority to mint tokens to treasury[PREFIX, program_id]
121    ///   4. `[signer]` Authority of vault
122    ///   5. `[]` Token program
123    MintFractionalShares(NumberOfShareArgs),
124
125    /// Withdraws shares from the treasury to a desired account.
126    ///   0. `[writable]` Initialized Destination account for the shares being withdrawn
127    ///   1. `[writable]` Fraction treasury
128    ///   2. `[]` The initialized active token vault
129    ///   3. `[]` PDA-based Transfer authority to move tokens from treasury to your destination[PREFIX, program_id]
130    ///   3. `[signer]` Authority of vault
131    ///   4. `[]` Token program
132    ///   5. `[]` Rent sysvar
133    WithdrawSharesFromTreasury(NumberOfShareArgs),
134
135    /// Returns shares to the vault if you wish to remove them from circulation.
136    ///   0. `[writable]` Initialized account from which shares will be withdrawn
137    ///   1. `[writable]` Fraction treasury
138    ///   2. `[]` The initialized active token vault
139    ///   3. `[signer]` Transfer authority to move tokens from your account to treasury
140    ///   3. `[signer]` Authority of vault
141    ///   4. `[]` Token program
142    AddSharesToTreasury(NumberOfShareArgs),
143
144    /// Helpful method that isn't necessary to use for main users of the app, but allows one to create/update
145    /// existing external price account fields if they are signers of this account.
146    /// Useful for testing purposes, and the CLI makes use of it as well so that you can verify logic.
147    ///   0. `[writable]` External price account
148    UpdateExternalPriceAccount(ExternalPriceAccount),
149
150    /// Sets the authority of the vault to a new authority.
151    ///
152    ///   0. `[writable]` Vault
153    ///   1. `[signer]` Vault authority
154    ///   2. `[]` New authority
155    SetAuthority,
156}
157
158/// Creates an InitVault instruction
159#[allow(clippy::too_many_arguments)]
160pub fn create_init_vault_instruction(
161    program_id: Pubkey,
162    fraction_mint: Pubkey,
163    redeem_treasury: Pubkey,
164    fraction_treasury: Pubkey,
165    vault: Pubkey,
166    vault_authority: Pubkey,
167    external_price_account: Pubkey,
168    allow_further_share_creation: bool,
169) -> Instruction {
170    Instruction {
171        program_id,
172        accounts: vec![
173            AccountMeta::new(fraction_mint, false),
174            AccountMeta::new(redeem_treasury, false),
175            AccountMeta::new(fraction_treasury, false),
176            AccountMeta::new(vault, false),
177            AccountMeta::new_readonly(vault_authority, false),
178            AccountMeta::new_readonly(external_price_account, false),
179            AccountMeta::new_readonly(spl_token::id(), false),
180            AccountMeta::new_readonly(sysvar::rent::id(), false),
181        ],
182        data: VaultInstruction::InitVault(InitVaultArgs {
183            allow_further_share_creation,
184        })
185        .try_to_vec()
186        .unwrap(),
187    }
188}
189
190/// Creates an UpdateExternalPriceAccount instruction
191#[allow(clippy::too_many_arguments)]
192pub fn create_update_external_price_account_instruction(
193    program_id: Pubkey,
194    external_price_account: Pubkey,
195    price_per_share: u64,
196    price_mint: Pubkey,
197    allowed_to_combine: bool,
198) -> Instruction {
199    Instruction {
200        program_id,
201        accounts: vec![AccountMeta::new(external_price_account, true)],
202        data: VaultInstruction::UpdateExternalPriceAccount(ExternalPriceAccount {
203            key: Key::ExternalAccountKeyV1,
204            price_per_share,
205            price_mint,
206            allowed_to_combine,
207        })
208        .try_to_vec()
209        .unwrap(),
210    }
211}
212
213/// Creates an AddTokenToInactiveVault instruction
214#[allow(clippy::too_many_arguments)]
215pub fn create_add_token_to_inactive_vault_instruction(
216    program_id: Pubkey,
217    safety_deposit_box: Pubkey,
218    token_account: Pubkey,
219    store: Pubkey,
220    vault: Pubkey,
221    vault_authority: Pubkey,
222    payer: Pubkey,
223    transfer_authority: Pubkey,
224    amount: u64,
225) -> Instruction {
226    Instruction {
227        program_id,
228        accounts: vec![
229            AccountMeta::new(safety_deposit_box, false),
230            AccountMeta::new(token_account, false),
231            AccountMeta::new(store, false),
232            AccountMeta::new(vault, false),
233            AccountMeta::new_readonly(vault_authority, true),
234            AccountMeta::new_readonly(payer, true),
235            AccountMeta::new_readonly(transfer_authority, true),
236            AccountMeta::new_readonly(spl_token::id(), false),
237            AccountMeta::new_readonly(sysvar::rent::id(), false),
238            AccountMeta::new_readonly(solana_program::system_program::id(), false),
239        ],
240        data: VaultInstruction::AddTokenToInactiveVault(AmountArgs { amount })
241            .try_to_vec()
242            .unwrap(),
243    }
244}
245
246/// Creates an ActivateVault instruction
247#[allow(clippy::too_many_arguments)]
248pub fn create_activate_vault_instruction(
249    program_id: Pubkey,
250    vault: Pubkey,
251    fraction_mint: Pubkey,
252    fraction_treasury: Pubkey,
253    fraction_mint_authority: Pubkey,
254    vault_authority: Pubkey,
255    number_of_shares: u64,
256) -> Instruction {
257    Instruction {
258        program_id,
259        accounts: vec![
260            AccountMeta::new(vault, false),
261            AccountMeta::new(fraction_mint, false),
262            AccountMeta::new(fraction_treasury, false),
263            AccountMeta::new_readonly(fraction_mint_authority, false),
264            AccountMeta::new_readonly(vault_authority, true),
265            AccountMeta::new_readonly(spl_token::id(), false),
266        ],
267        data: VaultInstruction::ActivateVault(NumberOfShareArgs { number_of_shares })
268            .try_to_vec()
269            .unwrap(),
270    }
271}
272
273/// Creates an CombineVault instruction
274#[allow(clippy::too_many_arguments)]
275pub fn create_combine_vault_instruction(
276    program_id: Pubkey,
277    vault: Pubkey,
278    outstanding_share_token_account: Pubkey,
279    paying_token_account: Pubkey,
280    fraction_mint: Pubkey,
281    fraction_treasury: Pubkey,
282    redeem_treasury: Pubkey,
283    new_authority: Pubkey,
284    vault_authority: Pubkey,
285    paying_transfer_authority: Pubkey,
286    uncirculated_burn_authority: Pubkey,
287    external_pricing_account: Pubkey,
288) -> Instruction {
289    Instruction {
290        program_id,
291        accounts: vec![
292            AccountMeta::new(vault, false),
293            AccountMeta::new(outstanding_share_token_account, false),
294            AccountMeta::new(paying_token_account, false),
295            AccountMeta::new(fraction_mint, false),
296            AccountMeta::new(fraction_treasury, false),
297            AccountMeta::new(redeem_treasury, false),
298            AccountMeta::new(new_authority, false),
299            AccountMeta::new_readonly(vault_authority, true),
300            AccountMeta::new_readonly(paying_transfer_authority, true),
301            AccountMeta::new_readonly(uncirculated_burn_authority, false),
302            AccountMeta::new_readonly(external_pricing_account, false),
303            AccountMeta::new_readonly(spl_token::id(), false),
304        ],
305        data: VaultInstruction::CombineVault.try_to_vec().unwrap(),
306    }
307}
308
309/// Creates an RedeemShares instruction
310#[allow(clippy::too_many_arguments)]
311pub fn create_redeem_shares_instruction(
312    program_id: Pubkey,
313    outstanding_shares_account: Pubkey,
314    proceeds_account: Pubkey,
315    fraction_mint: Pubkey,
316    redeem_treasury: Pubkey,
317    transfer_authority: Pubkey,
318    burn_authority: Pubkey,
319    vault: Pubkey,
320) -> Instruction {
321    Instruction {
322        program_id,
323        accounts: vec![
324            AccountMeta::new(outstanding_shares_account, false),
325            AccountMeta::new(proceeds_account, false),
326            AccountMeta::new(fraction_mint, false),
327            AccountMeta::new(redeem_treasury, false),
328            AccountMeta::new_readonly(transfer_authority, false),
329            AccountMeta::new_readonly(burn_authority, true),
330            AccountMeta::new_readonly(vault, false),
331            AccountMeta::new_readonly(spl_token::id(), false),
332            AccountMeta::new_readonly(sysvar::rent::id(), false),
333        ],
334        data: VaultInstruction::RedeemShares.try_to_vec().unwrap(),
335    }
336}
337
338#[allow(clippy::too_many_arguments)]
339pub fn create_withdraw_tokens_instruction(
340    program_id: Pubkey,
341    destination: Pubkey,
342    safety_deposit_box: Pubkey,
343    store: Pubkey,
344    vault: Pubkey,
345    fraction_mint: Pubkey,
346    vault_authority: Pubkey,
347    transfer_authority: Pubkey,
348    amount: u64,
349) -> Instruction {
350    Instruction {
351        program_id,
352        accounts: vec![
353            AccountMeta::new(destination, false),
354            AccountMeta::new(safety_deposit_box, false),
355            AccountMeta::new(store, false),
356            AccountMeta::new(vault, false),
357            AccountMeta::new_readonly(fraction_mint, false),
358            AccountMeta::new_readonly(vault_authority, true),
359            AccountMeta::new_readonly(transfer_authority, false),
360            AccountMeta::new_readonly(spl_token::id(), false),
361            AccountMeta::new_readonly(sysvar::rent::id(), false),
362        ],
363        data: VaultInstruction::WithdrawTokenFromSafetyDepositBox(AmountArgs { amount })
364            .try_to_vec()
365            .unwrap(),
366    }
367}
368
369#[allow(clippy::too_many_arguments)]
370pub fn create_mint_shares_instruction(
371    program_id: Pubkey,
372    fraction_treasury: Pubkey,
373    fraction_mint: Pubkey,
374    vault: Pubkey,
375    fraction_mint_authority: Pubkey,
376    vault_authority: Pubkey,
377    number_of_shares: u64,
378) -> Instruction {
379    Instruction {
380        program_id,
381        accounts: vec![
382            AccountMeta::new(fraction_treasury, false),
383            AccountMeta::new(fraction_mint, false),
384            AccountMeta::new_readonly(vault, false),
385            AccountMeta::new_readonly(fraction_mint_authority, false),
386            AccountMeta::new_readonly(vault_authority, true),
387            AccountMeta::new_readonly(spl_token::id(), false),
388        ],
389        data: VaultInstruction::MintFractionalShares(NumberOfShareArgs { number_of_shares })
390            .try_to_vec()
391            .unwrap(),
392    }
393}
394
395#[allow(clippy::too_many_arguments)]
396pub fn create_withdraw_shares_instruction(
397    program_id: Pubkey,
398    destination: Pubkey,
399    fraction_treasury: Pubkey,
400    vault: Pubkey,
401    transfer_authority: Pubkey,
402    vault_authority: Pubkey,
403    number_of_shares: u64,
404) -> Instruction {
405    Instruction {
406        program_id,
407        accounts: vec![
408            AccountMeta::new(destination, false),
409            AccountMeta::new(fraction_treasury, false),
410            AccountMeta::new_readonly(vault, false),
411            AccountMeta::new_readonly(transfer_authority, false),
412            AccountMeta::new_readonly(vault_authority, true),
413            AccountMeta::new_readonly(spl_token::id(), false),
414            AccountMeta::new_readonly(sysvar::rent::id(), false),
415        ],
416        data: VaultInstruction::WithdrawSharesFromTreasury(NumberOfShareArgs { number_of_shares })
417            .try_to_vec()
418            .unwrap(),
419    }
420}
421
422#[allow(clippy::too_many_arguments)]
423pub fn create_add_shares_instruction(
424    program_id: Pubkey,
425    source: Pubkey,
426    fraction_treasury: Pubkey,
427    vault: Pubkey,
428    transfer_authority: Pubkey,
429    vault_authority: Pubkey,
430    number_of_shares: u64,
431) -> Instruction {
432    Instruction {
433        program_id,
434        accounts: vec![
435            AccountMeta::new(source, false),
436            AccountMeta::new(fraction_treasury, false),
437            AccountMeta::new_readonly(vault, false),
438            AccountMeta::new_readonly(transfer_authority, true),
439            AccountMeta::new_readonly(vault_authority, true),
440            AccountMeta::new_readonly(spl_token::id(), false),
441            AccountMeta::new_readonly(sysvar::rent::id(), false),
442        ],
443        data: VaultInstruction::AddSharesToTreasury(NumberOfShareArgs { number_of_shares })
444            .try_to_vec()
445            .unwrap(),
446    }
447}
448
449pub fn create_set_authority_instruction(
450    program_id: Pubkey,
451    vault: Pubkey,
452    current_authority: Pubkey,
453    new_authority: Pubkey,
454) -> Instruction {
455    Instruction {
456        program_id,
457        accounts: vec![
458            AccountMeta::new(vault, false),
459            AccountMeta::new_readonly(current_authority, true),
460            AccountMeta::new_readonly(new_authority, false),
461        ],
462        data: VaultInstruction::SetAuthority.try_to_vec().unwrap(),
463    }
464}