1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
use derive_account;
use derive_builder;
use derive_context;
use derive_instruction;
use TokenStream;
use quote;
use ;
// -----------------
// #[derive(ShankAccount)]
// -----------------
/// Annotates a _struct_ that shank will consider an account containing de/serializable data.
///
/// # Field Attributes
///
/// ## `#[idl_type(...)]` attribute
///
/// This attribute allows you to override how Shank interprets a field's type when generating the IDL.
/// This is useful for:
///
/// 1. Fields with wrapper types that should be treated as their inner types in the IDL
/// 2. Fields storing enum values as primitives (like `u8`) that should be recognized as enums
/// 3. Fields with complex types that need simpler representations in the IDL
///
/// The attribute supports two formats:
///
/// 1. **String literal format**: `#[idl_type("TypeName")]`
/// 2. **Direct type format**: `#[idl_type(TypeName)]`
///
/// ```
/// use shank::ShankAccount;
///
/// #[derive(ShankAccount)]
/// pub struct MyAccount {
/// // Field stored as u8 but representing an enum
/// #[idl_type("MyEnum")]
/// pub enum_as_byte: u8,
///
/// // Field with a wrapper type that should be treated as a simpler type
/// #[idl_type("u64")]
/// pub wrapped_u64: CustomU64Wrapper,
/// }
/// ```
///
/// ## `#[padding]` attribute
///
/// Indicates that a field is used for padding and should be marked as such in the IDL.
///
/// ## `#[idl_name("name")]` attribute
///
/// Allows you to override the field name that appears in the IDL while keeping the original Rust field name.
///
/// ```
/// #[derive(ShankAccount)]
/// pub struct MyAccount {
/// #[idl_name("displayName")]
/// pub internal_name: String,
/// }
/// ```
///
/// ## `#[skip]` attribute
///
/// Excludes the field from the IDL entirely. The field will not appear in the generated IDL.
///
/// ```
/// #[derive(ShankAccount)]
/// pub struct MyAccount {
/// pub public_field: u64,
/// #[skip]
/// pub internal_only_field: String,
/// }
/// ```
///
/// # Example
///
/// ```
/// use shank::ShankAccount;
/// use borsh::{BorshDeserialize, BorshSerialize};
///
/// #[derive(Clone, BorshSerialize, BorshDeserialize, ShankAccount)]
/// pub struct Metadata {
/// pub update_authority: Pubkey,
/// pub mint: Pubkey,
/// pub primary_sale_happened: bool,
/// }
/// ```
///
/// # Seeds
///
/// You can include a `#[seeds]` annotation which allows shank to generate the following `impl`
/// methods for the particular account.
///
/// A seed takes one of the following patterns:
///
/// - `"literal"` this will be hardcoded into the seed/pda methods and does not need to be passed
/// via an argument
/// - `program_id` (known pubkey) this is the program id of the program which is passed to methods
/// - `label("description"[, type])` a seed of name _label_ with the provided description and an
/// optional type (if no type is provided `Pubkey` is assumed); this will be passed as an argument
///
/// Below is an example of each:
///
/// ```
/// #[derive(ShankAccount)]
/// #[seeds(
/// "lit:prefix", // a string literal which will be hard coded
/// program_id // the public key of the program which needs to be provided
/// pub_key_implicit("desc of the key"), // a public key which needs to be provided
/// pub_key("desc of the key", Pubkey), // same as the above, explicitly declaring as pubkey
/// id("desc of byte", u8), // a byte
/// name("desc of name", String) // a string
/// )]
/// struct AccountStructWithSeeds {
/// count: u8,
/// }
/// ```
/// When seeds are specified for an account it will derive the following _static_ methods for that
/// account:
///
/// ```
/// AccountName::shank_seeds<'a>(..) -> [&'a [u8]; Nusize]
/// AccountName::shank_seeds_with_bump<'a>(.., bump: &'a [u8; 1]) -> [&'a [u8]; Nusize]
///
/// AccountName::shank_pda(program_id: Pubkey, ..) -> (Pubkey, u8)
/// AccountName::shank_pda_with_bump(program_id: Pubkey, bump: u8, ..) -> (Pubkey, u8)
/// ```
///
///# Note
///
/// The fields of a _ShankAccount_ struct can reference other types as long as they are annotated
/// with `ShankType`, `BorshSerialize` or `BorshDeserialize`.
// -----------------
// #[derive(ShankInstruction)]
// -----------------
/// Annotates the program _Instruction_ `Enum` in order to include `#[account]` attributes.
///
/// The `#[account]` attributes indicate for each instruction _variant_ which accounts it expects
/// and how they should be configured.
///
/// # `#[account]` attribute
///
/// This attribute allows you to configure each account that is provided to the particular
/// instruction. These annotations need to follow the order in which the accounts are provided.
/// They take the following general form:
///
/// ```
/// #[account(index?, writable?, (signer|optional_signer)?, optional?, name="<account_name>", desc?="optional description")]
/// ```
///
/// - `index`: optionally provides the account index in the provided accounts array which needs to
/// match its position of `#[account]` attributes
/// - `signer` | `sign` | `sig`: indicates that the account is _signer_
/// - `optional_signer`: indicates that the account is _optional_signer_
/// - `writable` | `write` | `writ` | `mut`: indicates that the account is _writable_ which means it may be
/// mutated as part of processing the particular instruction
/// - `optional | option | opt`: indicates that this account is optional
/// - `name`: (required) provides the name for the account
/// - `desc` | `description` | `docs`: allows to provide a description of the account
///
/// When the `optional` attribute is added to an account, shank will mark it such that its value should default
/// to the `progam_id` if it is not provided by the client. Thus the position of optional accounts is static and
/// optional accounts that are set can follow ones that are not.
///
/// # Known Accounts
///
/// If an account `name` matches either of the a _known_ accounts indicated below then
/// [solita](https://github.com/metaplex-foundation/solita) generated SDK code won't require providing
/// it as the program id is known.
///
/// - `token_program` uses `TOKEN_PROGRAM_ID`
/// - `ata_program` uses `ASSOCIATED_TOKEN_PROGRAM_ID`
/// - `system_program` uses `SystemProgram.programId`
/// - `rent` uses `SYSVAR_RENT_PUBKEY`
///
/// # Optional Accounts Strategies
///
/// The default strategy (without `#[legacy_optional_accounts_strategy]`) is to set the `program_id` in place
/// of an optional account not set by the client. When the `#[legacy_optional_accounts_strategy]` is added,
/// shank will instead omit unset optional accounts from the accounts array.
///
/// **NOTE**: shank doesn't do anything different here aside from setting a flag for the
/// particular instruction. Thus adding that strategy to an instruction enum is merely advisory and
/// will is expected to be properly respected by code generator tools like
/// [kinobi](https://github.com/metaplex-foundation/kinobi) and [solita](https://github.com/metaplex-foundation/solita).
///
/// # Examples
///
/// ```
/// use borsh::{BorshDeserialize, BorshSerialize};
/// use shank::ShankInstruction;
/// #[derive(Debug, Clone, ShankInstruction, BorshSerialize, BorshDeserialize)]
/// #[rustfmt::skip]
/// pub enum VaultInstruction {
/// /// Initialize a token vault, starts inactivate. Add tokens in subsequent instructions, then activate.
/// #[account(0, writable, name="fraction_mint",
/// desc="Initialized fractional share mint with 0 tokens in supply, authority on mint must be pda of program with seed [prefix, programid]")]
/// #[account(1, writable, name="redeem_treasury",
/// desc = "Initialized redeem treasury token account with 0 tokens in supply, owner of account must be pda of program like above")]
/// #[account(2, writable, name="fraction_treasury",
/// desc = "Initialized fraction treasury token account with 0 tokens in supply, owner of account must be pda of program like above")]
/// #[account(3, writable, name="vault",
/// desc = "Uninitialized vault account")]
/// #[account(4, optional_signer, name="authority",
/// desc = "Authority on the vault")]
/// #[account(5, name="pricing_lookup_address",
/// desc = "Pricing Lookup Address")]
/// #[account(6, name="token_program",
/// desc = "Token program")]
/// #[account(7, name="rent",
/// desc = "Rent sysvar")]
/// InitVault(InitVaultArgs),
///
/// /// Activates the vault, distributing initial shares into the fraction treasury.
/// /// Tokens can no longer be removed in this state until Combination.
/// #[account(0, writable, name="vault", desc = "Initialized inactivated fractionalized token vault")]
/// #[account(1, writable, name="fraction_mint", desc = "Fraction mint")]
/// #[account(2, writable, name="fraction_treasury", desc = "Fraction treasury")]
/// #[account(3, name="fraction_mint_authority", desc = "Fraction mint authority for the program - seed of [PREFIX, program_id]")]
/// #[account(4, signer, name="vault_authority", desc = "Authority on the vault")]
/// #[account(5, name="token_program", desc = "Token program")]
/// ActivateVault(NumberOfShareArgs)
/// }
/// ```
// -----------------
// #[derive(ShankBuilder)]
// -----------------
/// Generates instruction builders for each annotated instruction.
///
/// An instruction builder is an _struct_ that contains all the accounts for an instruction. You can
/// also include `#[args]` attributes to specify additional arguments that are passed to the builder.
///
///
/// # Example
///
/// When you annotate your instruction with `#[derive(ShankBuilder)]`:
///
/// ```
/// use borsh::{BorshDeserialize, BorshSerialize};
/// use shank::ShankBuilder;
/// #[derive(Debug, Clone, ShankBuilder, BorshSerialize, BorshDeserialize)]
/// #[rustfmt::skip]
/// pub enum Instruction {
/// /// This instruction stores an amout in the vault.
/// #[account(0, writable, name="vault", desc="Vault account")]
/// #[account(1, signer, name="authority", desc = "Authority of the vault")]
/// #[account(2, signer, writable, name = "payer", desc = "Payer")]
/// #[account(3, name = "system_program", desc = "System program")]
/// #[args(additional_accounts: Vec<AccountMeta>)]
/// Create(CreateArgs)
/// }
/// ```
///
/// Shank will generate a `CreateBuilder` _struct_ in a submodule called `builders`. The builder can be used
/// to define the accounts and arguments for the instruction:
///
/// ```
/// let create_ix = CreateBuilder::new()
/// .vault(vault_pubkey)
/// .authority(authority_pubkey)
/// .payer(payer_pubkey)
/// .build(additional_accounts)
/// .instruction();
/// ```
// -----------------
// #[derive(ShankContext)]
// -----------------
/// Generates an accounts _struct_ for each instruction.
///
/// The _struct_ will contain all shank annotated accounts and the _impl_ block
/// will initialize them from the accounts array. This struct can be used in combination
/// with a `Context` to provide access to accounts by name. The accounts _strct_ supports
/// the use of optional accounts, which would generate an account field with an
/// `Option<AccountInfo<'a>>` type.
///
/// # Example
///
/// When you annotate your instruction with `#[derive(ShankContext)]`:
///
/// ```
/// use borsh::{BorshDeserialize, BorshSerialize};
/// use shank::ShankContext;
/// #[derive(Debug, Clone, ShankContext, BorshSerialize, BorshDeserialize)]
/// #[rustfmt::skip]
/// pub enum Instruction {
/// /// This instruction stores an amout in the vault.
/// #[account(0, writable, name="vault", desc="Vault account")]
/// #[account(1, signer, name="authority", desc = "Authority of the vault")]
/// #[account(2, signer, writable, name = "payer", desc = "Payer")]
/// #[account(3, name = "system_program", desc = "System program")]
/// #[args(amount: u64)]
/// Create(CreateOrUpdateArgs)
/// }
/// ```
///
/// A `CreateAccounts` and a generic `Context` _structs_ will be generated, which can be used to
/// access each account by name in your processor implementation:
///
/// ```
/// pub fn process_create<'a>(
/// program_id: &Pubkey,
/// accounts: &'a [AccountInfo<'a>],
/// instruction_data: &[u8],
/// ) -> ProgramResult {
/// let context = CreateAccounts::context(accounts)?;
///
/// msg!("{}", context.accounts.vault.key);
/// msg!("{}", context.accounts.authority.key);
/// msg!("{}", context.accounts.payer.key);
/// ...
/// }
/// ```
// -----------------
// #[derive(ShankType)]
// -----------------
/// Annotates a _struct_ or _enum_ that shank will consider a type containing de/serializable data.
///
/// The macro does not generate any code. The annotation is used to indicate to shank-idl that the
/// the type should be included in the program's IDL.
///
/// # Example
///
/// ```
/// use shank::ShankType;
///
/// #[derive(ShankType)]
/// pub struct Metadata {
/// pub update_authority: Pubkey,
/// pub mint: Pubkey,
/// pub primary_sale_happened: bool,
/// }
/// ```
///
/// # Type Attributes
///
/// ## `#[pod_sentinel(...)]` attribute
///
/// Specifies the sentinel value for custom types used with `PodOption`. This is required when
/// your type is wrapped in `PodOption<T>` for fixed-size optional serialization (bytemuck/podded).
///
/// The sentinel value is a comma-separated list of u8 decimal integers (0-255) that represents
/// the "None" state for this type.
///
/// ```
/// use shank::ShankType;
///
/// #[derive(ShankType)]
/// #[pod_sentinel(255, 255, 255, 255)]
/// pub struct CustomU32Wrapper {
/// pub value: u32,
/// }
///
/// // Now this type can be used with PodOption:
/// #[derive(ShankAccount)]
/// pub struct MyAccount {
/// pub optional_field: PodOption<CustomU32Wrapper>,
/// }
/// ```
///
///# Note
///
/// The fields of a _ShankType_ struct or enum can reference other types as long as they are annotated
/// with `ShankType`, `BorshSerialize` or `BorshDeserialize`.