manifest/program/
instruction.rs

1use num_enum::TryFromPrimitive;
2use shank::ShankInstruction;
3
4/// Instructions available for the Manifest program
5#[repr(u8)]
6#[derive(TryFromPrimitive, Debug, Copy, Clone, ShankInstruction, PartialEq, Eq)]
7#[rustfmt::skip]
8pub enum ManifestInstruction {
9    /// Create a market
10    #[account(0, writable, signer, name = "payer", desc = "Payer")]
11    #[account(1, writable, name = "market", desc = "Account holding all market state")]
12    #[account(2, name = "system_program", desc = "System program")]
13    #[account(3, name = "base_mint", desc = "Base mint")]
14    #[account(4, name = "quote_mint", desc = "Quote mint")]
15    #[account(5, writable, name = "base_vault", desc = "Base vault PDA, seeds are [b'vault', market, base_mint]")]
16    #[account(6, writable, name = "quote_vault", desc = "Quote vault PDA, seeds are [b'vault', market, quote_mint]")]
17    #[account(7, name = "token_program", desc = "Token program")]
18    // Always include both token programs so we can initialize both types of token vaults if needed.
19    #[account(8, name = "token_program_22", desc = "Token program 22")]
20    CreateMarket = 0,
21
22    /// Allocate a seat
23    #[account(0, writable, signer, name = "payer", desc = "Payer")]
24    #[account(1, writable, name = "market", desc = "Account holding all market state")]
25    #[account(2, name = "system_program", desc = "System program")]
26    ClaimSeat = 1,
27
28    /// Deposit
29    #[account(0, writable, signer, name = "payer", desc = "Payer")]
30    #[account(1, writable, name = "market", desc = "Account holding all market state")]
31    #[account(2, writable, name = "trader_token", desc = "Trader token account")]
32    #[account(3, writable, name = "vault", desc = "Vault PDA, seeds are [b'vault', market, mint]")]
33    #[account(4, name = "token_program", desc = "Token program(22), should be the version that aligns with the token being used")]
34    #[account(5, name = "mint", desc = "Required for token22 transfer_checked")]
35    Deposit = 2,
36
37    /// Withdraw
38    #[account(0, writable, signer, name = "payer", desc = "Payer")]
39    #[account(1, writable, name = "market", desc = "Account holding all market state")]
40    #[account(2, writable, name = "trader_token", desc = "Trader token account")]
41    #[account(3, writable, name = "vault", desc = "Vault PDA, seeds are [b'vault', market, mint]")]
42    #[account(4, name = "token_program", desc = "Token program(22), should be the version that aligns with the token being used")]
43    #[account(5, name = "mint", desc = "Required for token22 transfer_checked")]
44    Withdraw = 3,
45
46    /// Places an order using funds in a wallet instead of on deposit
47    #[account(0, writable, signer, name = "payer", desc = "Payer")]
48    #[account(1, writable, name = "market", desc = "Account holding all market state")]
49    #[account(2, name = "system_program", desc = "System program")]
50    #[account(3, writable, name = "trader_base", desc = "Trader base token account")]
51    #[account(4, writable, name = "trader_quote", desc = "Trader quote token account")]
52    #[account(5, writable, name = "base_vault", desc = "Base vault PDA, seeds are [b'vault', market_address, base_mint]")]
53    #[account(6, writable, name = "quote_vault", desc = "Quote vault PDA, seeds are [b'vault', market_address, quote_mint]")]
54    #[account(7, name = "token_program_base", desc = "Token program(22) base")]
55    #[account(8, optional, name = "base_mint", desc = "Base mint, only included if base is Token22, otherwise not required")]
56    #[account(9, optional, name = "token_program_quote", desc = "Token program(22) quote. Optional. Only include if different from base")]
57    #[account(10, optional, name = "quote_mint", desc = "Quote mint, only included if base is Token22, otherwise not required")]
58    #[account(11, writable, optional, name = "global", desc = "Global account")]
59    #[account(12, writable, optional, name = "global_vault", desc = "Global vault")]
60    Swap = 4,
61
62    /// Expand a market.
63    /// 
64    /// This is not used in normal operations because expansion happens within
65    /// instructions that could require it.
66    /// This is useful for when rent payer != transaction signer.
67    #[account(0, writable, signer, name = "payer", desc = "Payer")]
68    #[account(1, writable, name = "market", desc = "Account holding all market state")]
69    #[account(2, name = "system_program", desc = "System program")]
70    Expand = 5,
71
72    /// Batch update with multiple place orders and cancels.
73    #[account(0, writable, signer, name = "payer", desc = "Payer")]
74    #[account(1, writable, name = "market", desc = "Account holding all market state")]
75    #[account(2, name = "system_program", desc = "System program")]
76    #[account(3, optional, name = "base_mint", desc = "Mint for the base global account")]
77    #[account(4, optional, writable, name = "base_global", desc = "Base global account")]
78    #[account(5, optional, name = "base_global_vault", desc = "Base global vault")]
79    #[account(6, optional, name = "base_market_vault", desc = "Base market vault")]
80    #[account(7, optional, name = "base_token_program", desc = "Token program(22)")]
81    #[account(8, optional, name = "quote_mint", desc = "Mint for this global account")]
82    #[account(9, optional, writable, name = "quote_global", desc = "Quote global account")]
83    #[account(10, optional, name = "quote_global_vault", desc = "Quote global vault")]
84    #[account(11, optional, name = "quote_market_vault", desc = "Quote market vault")]
85    #[account(12, optional, name = "quote_token_program", desc = "Token program(22)")]
86    BatchUpdate = 6,
87
88    /// Create global account for a given token.
89    #[account(0, writable, signer, name = "payer", desc = "Payer")]
90    #[account(1, writable, name = "global", desc = "Global account")]
91    #[account(2, name = "system_program", desc = "System program")]
92    #[account(3, name = "mint", desc = "Mint for this global account")]
93    #[account(4, writable, name = "global_vault", desc = "Global vault")]
94    #[account(5, name = "token_program", desc = "Token program(22)")]
95    GlobalCreate = 7,
96
97    /// Add a trader to the global account.
98    #[account(0, writable, signer, name = "payer", desc = "Payer")]
99    #[account(1, writable, name = "global", desc = "Global account")]
100    #[account(2, name = "system_program", desc = "System program")]
101    GlobalAddTrader = 8,
102
103    /// Deposit into global account for a given token.
104    #[account(0, writable, signer, name = "payer", desc = "Payer")]
105    #[account(1, writable, name = "global", desc = "Global account")]
106    #[account(2, name = "mint", desc = "Mint for this global account")]
107    #[account(3, writable, name = "global_vault", desc = "Global vault")]
108    #[account(4, writable, name = "trader_token", desc = "Trader token account")]
109    #[account(5, name = "token_program", desc = "Token program(22)")]
110    GlobalDeposit = 9,
111
112    /// Withdraw from global account for a given token.
113    #[account(0, writable, signer, name = "payer", desc = "Payer")]
114    #[account(1, writable, name = "global", desc = "Global account")]
115    #[account(2, name = "mint", desc = "Mint for this global account")]
116    #[account(3, writable, name = "global_vault", desc = "Global vault")]
117    #[account(4, writable, name = "trader_token", desc = "Trader token account")]
118    #[account(5, name = "token_program", desc = "Token program(22)")]
119    GlobalWithdraw = 10,
120
121    /// Evict another trader from the global account.
122    #[account(0, writable, signer, name = "payer", desc = "Payer")]
123    #[account(1, writable, name = "global", desc = "Global account")]
124    #[account(2, name = "mint", desc = "Mint for this global account")]
125    #[account(3, writable, name = "global_vault", desc = "Global vault")]
126    #[account(4, name = "trader_token", desc = "Trader token account")]
127    #[account(5, name = "evictee_token", desc = "Evictee token account")]
128    #[account(6, name = "token_program", desc = "Token program(22)")]
129    GlobalEvict = 11,
130
131    /// Removes an order from a market that cannot be filled. There are 3
132    /// reasons. It is expired, the global trader got evicted, or the global
133    /// trader no longer has deposited the funds to back the order. This
134    /// function results in cleaner orderbooks which helps reduce variance and
135    /// thus compute unit estimates for traders. It is incentivized by receiving
136    /// gas prepayment deposits. This is not required for normal operation of
137    /// market. It exists as a deterrent to unfillable and unmaintained global
138    /// spam.
139    #[account(0, writable, signer, name = "payer", desc = "Payer for this tx, receiver of rent deposit")]
140    #[account(1, writable, name = "market", desc = "Account holding all market state")]
141    #[account(2, name = "system_program", desc = "System program")]
142    #[account(3, writable, name = "global", desc = "Global account")]
143    GlobalClean = 12,
144
145    
146    /// Places an order using funds in a wallet instead of on deposit. Separates
147    /// the owner of the token accounts and the payer. This allows routers to
148    /// swap and have intermediate hops go through PDAs, rather than all token
149    /// accounts owned by the user.
150    #[account(0, writable, signer, name = "payer", desc = "Payer")]
151    #[account(1, writable, signer, name = "owner", desc = "Owner")]
152    #[account(2, writable, name = "market", desc = "Account holding all market state")]
153    #[account(3, name = "system_program", desc = "System program")]
154    #[account(4, writable, name = "trader_base", desc = "Trader base token account")]
155    #[account(5, writable, name = "trader_quote", desc = "Trader quote token account")]
156    #[account(6, writable, name = "base_vault", desc = "Base vault PDA, seeds are [b'vault', market_address, base_mint]")]
157    #[account(7, writable, name = "quote_vault", desc = "Quote vault PDA, seeds are [b'vault', market_address, quote_mint]")]
158    #[account(8, name = "token_program_base", desc = "Token program(22) base")]
159    #[account(9, optional, name = "base_mint", desc = "Base mint, only included if base is Token22, otherwise not required")]
160    #[account(10, optional, name = "token_program_quote", desc = "Token program(22) quote. Optional. Only include if different from base")]
161    #[account(11, optional, name = "quote_mint", desc = "Quote mint, only included if base is Token22, otherwise not required")]
162    #[account(12, writable, optional, name = "global", desc = "Global account")]
163    #[account(13, writable, optional, name = "global_vault", desc = "Global vault")]
164    SwapV2 = 13,
165}
166
167impl ManifestInstruction {
168    pub fn to_vec(&self) -> Vec<u8> {
169        vec![*self as u8]
170    }
171}
172
173#[test]
174fn test_instruction_serialization() {
175    let num_instructions: u8 = 13;
176    for i in 0..=255 {
177        let instruction: ManifestInstruction = match ManifestInstruction::try_from(i) {
178            Ok(j) => {
179                assert!(i <= num_instructions);
180                j
181            }
182            Err(_) => {
183                assert!(i > num_instructions);
184                continue;
185            }
186        };
187        assert_eq!(instruction as u8, i);
188    }
189}
190
191#[test]
192fn test_to_vec() {
193    let create_market_ix = ManifestInstruction::CreateMarket;
194    let vec = create_market_ix.to_vec();
195    assert_eq!(*vec.first().unwrap(), 0);
196}