Skip to content

#[seeds] should support [u8; N] fixed-size byte array seed types (N ≤ 32) #213

@lucky-ivanius

Description

@lucky-ivanius

Use case

When defining PDAs keyed by hash values, namespace identifiers, or other fixed-size byte identifiers, there is no clean way to express this in the #[seeds] attribute.

A concrete example — a Registry account keyed by a SHA-256 hash:

#[account(discriminator = 2)]
#[seeds(b"registry", hash: [u8; 32])]  // ❌ compile error
pub struct Registry {
    pub hash: [u8; 32],
    pub bump: u8,
}

This fails with:

error: unsupported seed type; expected Address, u8, u16, u32, or u64

The Address workaround is available for [u8; 32] but is semantically wrong. Address carries the meaning of a Solana public key — it implies an on-curve point, a signer, or a program account. Using it for a SHA-256 hash is misleading both to readers and to tooling (IDL generators, clients, auditors):

#[seeds(b"registry", hash: Address)]  // ✅ compiles, but wrong type semantics

Callers are then forced to cast or transmute a [u8; 32] into an Address at every call site, which pollutes the API with an incorrect type that will confuse anyone reading the code.

For [u8; 16] (a namespace identifier, for example) or any other size below 32, there is no workaround at all.

This matters because all three of these are valid Solana seeds at the protocol level — MAX_SEED_LEN = 32 is the only constraint, and a [u8; N] for N ≤ 32 satisfies it exactly. Anchor supports this natively by accepting any expression that coerces to &[u8] in its seed arrays.

Proposed solution

Add [u8; N] (N ≤ 32) as a recognized seed type in the #[seeds] attribute:

#[seeds(b"registry", hash: [u8; 32])]   // SHA-256 hash or arbitrary 32-byte ID
#[seeds(b"namespace", ns:  [u8; 16])]   // namespace identifier
#[seeds(b"slot",     key:  [u8; 8])]    // arbitrary 8-byte identifier

In derive/src/seeds.rs, this would involve:

  1. Adding a Bytes(usize) variant to SeedType
  2. Parsing syn::Type::Array in addition to Ident in the SeedsAttr parser
  3. Rejecting N > 32 at macro expansion time with a clear error (rather than relying on the runtime MAX_SEED_LEN panic)
  4. field_type[u8; N], param_type[u8; N], slice_expr&#access (no conversion needed — unlike scalars, it's already bytes)

The change is additive and does not affect any existing seed definitions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions