Skip to content

ADR-001: Recipient and Mint in PDA Seeds

Solana PDAs (Program Derived Addresses) require a set of seeds that deterministically generate a unique address. The initial architecture documentation proposed seed layouts that did not include the recipient or mint in the derivation path:

  1. ["vesting", creator, mint, vesting_count] — recipient verified via has_one constraint
  2. ["stream", creator, recipient] — one stream per (creator, recipient) pair, no mint in seeds (cross-token collisions)

The stub code also used ["stream", creator, recipient].

We needed to decide which seed layout to use for the StreamAccount PDA, balancing address uniqueness, safety invariants, and gas cost.

Use ["stream", creator, recipient, mint, vesting_count] as the PDA seed layout.

The recipient and mint are both included in the derivation path. Address uniqueness is guaranteed by the combination of (creator, recipient, mint, vesting_count).

LayoutProsCons
["creator", mint, vesting_count] + has_one(recipient)Saves 32 bytes of seed dataAddress doesn’t prove beneficiary; recipient set-race possible
["stream", creator, recipient]Simple, no nonce needed if 1:1Only one stream per pair; no cross-token support
["stream", creator, recipient, mint, vesting_count] (chosen)Cryptographic beneficiary proof; unlimited streams64 extra bytes in seed derivation
  • Cryptographic beneficiary commitment: The PDA address itself proves who the stream is for. Even if account data is corrupted, the address is an immutable proof of the recipient. This is an extra safety invariant beyond Anchor’s has_one constraint.
  • Cross-token support: Mint in the seed prevents address collisions between streams for different tokens sent to the same (creator, recipient) pair. A founder can vest USDC and their own token to the same recipient.
  • Unlimited streams: The vesting_count nonce allows the same (creator, recipient, mint) triple to have unlimited streams — useful for multi-tranche vesting schedules.
  • Milestone streams follow the same pattern: ["milestone-stream", creator, recipient, mint, vesting_count] mirrors the layout, keeping mental model consistent.
  • Immutable recipient: The recipient cannot be changed after creation without closing and recreating the stream. This is intentional — recipient immutability is a protocol invariant, not a limitation.
  • Longer PDA derivation: 5 seed components instead of 3. The cost is negligible (PDA derivation is off-chain).