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:
- Adding a
Bytes(usize) variant to SeedType
- Parsing
syn::Type::Array in addition to Ident in the SeedsAttr parser
- Rejecting N > 32 at macro expansion time with a clear error (rather than relying on the runtime
MAX_SEED_LEN panic)
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.
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
Registryaccount keyed by a SHA-256 hash:This fails with:
The
Addressworkaround is available for[u8; 32]but is semantically wrong.Addresscarries 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):Callers are then forced to cast or transmute a
[u8; 32]into anAddressat 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 = 32is 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:In
derive/src/seeds.rs, this would involve:Bytes(usize)variant toSeedTypesyn::Type::Arrayin addition toIdentin theSeedsAttrparserMAX_SEED_LENpanic)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.