#[derive(AccountSet)]
{
// Attributes available to this derive:
#[account_set]
#[decode]
#[validate]
#[cleanup]
#[idl]
#[single_account_set]
}
Expand description
Derives AccountSet lifecycle traits and AccountSetToIdl for a struct.
The AccountSet proc macro generates implementations for the three core traits:
AccountSetDecode- Decodes accounts from&[AccountInfo]arraysAccountSetValidate- Validates decoded accountsAccountSetCleanup- Performs cleanup operations after instruction execution
It also generates client-side implementations:
CpiAccountSet- Cross-program invocation account handlingClientAccountSet- Client-side account metadata generation- `AccountSetToIdl
This macro creates a comprehensive account management system that handles account validation, decoding from account info arrays, cleanup operations, and IDL generation for Solana programs.
§Integration with StarFrameInstruction
When using AccountSet with StarFrameInstruction, the argument types specified in field-level
attributes must correspond to the argument types from InstructionArgs. The arg parameter
in field attributes should match the types available from the instruction’s decode, validate,
run, and cleanup argument types.
§Struct-level Attributes
§#[account_set(skip_client_account_set, skip_cpi_account_set, skip_default_decode, skip_default_validate, skip_default_cleanup, skip_default_idl)]
Controls which implementations are generated:
skip_client_account_set- Skips generatingClientAccountSetimplementationskip_cpi_account_set- Skips generatingCpiAccountSetimplementationskip_default_decode- Skips generating defaultAccountSetDecodeimplementationskip_default_validate- Skips generating defaultAccountSetValidateimplementationskip_default_cleanup- Skips generating defaultAccountSetCleanupimplementationskip_default_idl- Skips generating default IDL implementations
§#[decode(id = <str>, arg = <type>, generics = <generics>, inline_always)]
Define custom decode implementations with specific arguments:
id = <str>- Unique identifier for this decode variant (optional, defaults to no id)arg = <type>- Type of argument passed to decode functionsgenerics = <generics>- Additional generic parameters for this decode implementationinline_always- Whether to add#[inline(always)]to the decode implementation (by default#[inline]is added)
§#[validate(id = <str>, arg = <type>, generics = <generics>, before_validation = <expr>, extra_validation = <expr>, inline_always)]
Define custom validation implementations:
id = <str>- Unique identifier for this validate variant (optional, defaults to no id)arg = <type>- Type of argument passed to validate functionsgenerics = <generics>- Additional generic parameters for this validate implementationbefore_validation = <expr>- Expression to execute before field validationextra_validation = <expr>- Expression to execute after field validationinline_always- Whether to add#[inline(always)]to the validate implementation (by default#[inline]is added)
§#[cleanup(id = <str>, generics = <generics>, arg = <type>, extra_cleanup = <expr>, inline_always)]
Define custom cleanup implementations:
id = <str>- Unique identifier for this cleanup variantgenerics = <generics>- Generic parameters for this cleanup implementationarg = <type>- Type of argument passed to cleanup functionsextra_cleanup = <expr>- Cleanup expression to execute after field cleanupinline_always- Whether to add#[inline(always)]to the cleanup implementation (by default#[inline]is added)
§#[idl(id = <str>, arg = <type>, generics = <generics>)]
Define custom IDL generation implementations:
id = <str>- Unique identifier for this IDL variant (optional, defaults to no id)arg = <type>- Type of argument passed to IDL functionsgenerics = <generics>- Additional generic parameters for this IDL implementation
§Field-level Attributes
§#[account_set(skip = <TokenStream>)]
Skip this field during account set processing. The field will be initialized with the provided default value.
§#[single_account_set(signer, writable, meta = <expr>, skip_*)]
Mark a field as a single account set. This indicates that the AccountSet contains only one account and all account set traits should be passed through to this flagged field. Only one field can have this attribute.
Options:
signer- Mark this account as a signerwritable- Mark this account as writablemeta = <expr>- Custom metadata expressionskip_signed_account- SkipSignedAccounttrait implementationskip_writable_account- SkipWritableAccounttrait implementationskip_has_inner_type- SkipHasInnerTypetrait implementationskip_has_owner_program- SkipHasOwnerProgramtrait implementationskip_has_seeds- SkipHasSeedstrait implementationskip_can_init_seeds- SkipCanInitSeedstrait implementationskip_can_init_account- SkipCanInitAccounttrait implementation
When a field is marked with #[single_account_set], the generated AccountSet implementation will:
- Implement
SingleAccountSetand delegate to the marked field - Pass through
CpiAccountSetandClientAccountSetimplementations - Forward trait implementations like
SignedAccount,WritableAccount,HasSeeds, etc.
§#[validate(id = <str>, funder, recipient, skip, requires = [<field>, ...], arg = <expr>, temp = <expr>, arg_ty = <type>, address = <expr>)]
Pass arguments to field validation:
id = <str>- Which validate variant this field participates in, to enable multipleAccountSetValidateimplementationsfunder- Mark this field as the funder for the Context cache (only one field can be marked as funder)recipient- Mark this field as the recipient for the Context cache (only one field can be marked as recipient)skip- Skip validation for this fieldrequires = [<field>, ...]- List of fields that must be validated before this fieldarg = <expr>- Argument to pass to the field’s `AccountSetValidate`` functiontemp = <expr>- Temporary variable expression to use witharg(requiresargto be specified)arg_ty = <type>- Type of the validation argument. Usually inferred, but can be specified to get better error messagesaddress = <expr>- Check that the field’s key matches this address, expr must return a&Pubkey
§#[decode(id = <str>, arg = <expr>)]
Pass arguments to field decoding:
id = <str>- Which decode variant this field participates in, to enable multipleAccountSetDecodeimplementationsarg = <expr>- Argument to pass to the field’sAccountSetDecodefunction
§#[cleanup(id = <str>, arg = <expr>)]
Pass arguments to field cleanup:
id = <str>- Which cleanup variant this field participates in, to enable multipleAccountSetCleanupimplementationsarg = <expr>- Argument to pass to the field’sAccountSetCleanupfunctionnormalize_rent- Mutually exclusive witharg, alias forarg = NormalizeRent(())
§#[idl(id = <str>, arg = <expr>, address = <expr>)]
Pass arguments to IDL generation:
id = <str>- Which IDL variant this field participates in, to enable multipleAccountSetToIdlimplementationsarg = <expr>- Argument to pass to the field’sAccountSetToIdlfunction for IDL generationaddress = <expr>- Address expression for single account IDL generation, expr must return aPubkey
§Examples
§Basic Account Set
use star_frame::prelude::*;
#[derive(AccountSet)]
pub struct BasicAccounts {
pub authority: Signer,
pub account: Mut<SystemAccount>,
pub system_program: Program<System>,
}§Account Set with Custom Arguments
use star_frame::prelude::*;
#[derive(AccountSet)]
#[decode(arg = usize)]
#[validate(arg = String, extra_validation = self.check_authority(arg))]
pub struct CustomAccounts {
pub authority: Signer,
// One of Vec's AccountSetDecode implementations takes in a usize to specify the number of accounts to decode, so it will try to decode `arg * 2` (for some reason?) accounts
// which will be passed to the `AccountSetDecode` function from StarFrameInstruction as the decode arg
#[decode(arg = arg * 2)]
pub accounts: Vec<SystemAccount>,
}
impl CustomAccounts {
fn check_authority(&self, arg: String) -> Result<()> {
todo!("check stuff")
}
}By setting the decode arg to usize, and validate to String, any StarFrameInstruction using this set must have an InstructionArgs implementation that returns those types.
§Single Account Set Newtype
use star_frame::{prelude::*, derive_more};
#[derive(AccountSet, derive_more::Deref, derive_more::DerefMut, Debug)]
pub struct WrappedCounter(#[single_account_set] Account<CounterAccount>);This creates a newtype wrapper that implements AccountSet and passes through all account
traits to the inner Account<CounterAccount>. The signer and writable flags modify
the account’s metadata for CPI and client usage. This will propagate all of the account_set::modifier
marker traits from the inner account to the newtype.