ShankAccount

Derive Macro ShankAccount 

Source
#[derive(ShankAccount)]
{
    // Attributes available to this derive:
    #[padding]
    #[seeds]
    #[idl_type]
    #[idl_name]
    #[skip]
    #[pod_sentinel]
}
Expand description

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.