PDAs & Account Storage
Technical details of Program Derived Address (PDA) seed derivation and on-chain account data layout.
Every tag registered on TIP is stored as an individual account on the Solana blockchain owned by the tip_registry program.
Seed Derivation Scheme
Tag accounts are Program Derived Addresses (PDAs). Because PDAs are derived deterministically without a private key, tag uniqueness is enforced directly by Solana runtime account initialization.
The PDA for any handle is derived using two seed byte arrays:
import { PublicKey } from "@solana/web3.js";
const [pda, bump] = PublicKey.findProgramAddressSync(
[
Buffer.from("tag", "utf-8"),
Buffer.from(normalizedTag, "utf-8"), // e.g. "alice"
],
PROGRAM_ID
);Deterministic Uniqueness
Because normalizeTag("Alice") produces "alice", there is exactly one PDA address possible for @alice on the entire Solana cluster. Attempts to register @alice a second time fail at the Solana runtime level because the account already exists.
On-Chain Account Layout
Each tag account stores a binary struct with the following layout:
// Rust Account Struct (programs/tip-registry/src/state.rs)
pub struct TagAccount {
pub discriminator: [u8; 8], // Anchor/Borsh 8-byte discriminator
pub tag: String, // Max 32 UTF-8 bytes (stored with 4-byte length prefix)
pub owner: Pubkey, // 32-byte Solana Public Key (Tag Owner)
pub wallet: Pubkey, // 32-byte Solana Public Key (Payment Destination)
pub bump: u8, // 1-byte PDA canonical bump
}Field Definitions
discriminator([u8; 8]): First 8 bytes of the SHA-256 hash ofaccount:TagAccount. Ensures the account type cannot be confused with other program accounts.tag(String): The canonical normalized handle (e.g.,"alice").owner(Pubkey): The wallet that registered the tag. Only this pubkey can sign transactions to updatewallet.wallet(Pubkey): The target address where funds should be delivered when sending tokens or SOL to@alice. Defaults toownerat registration.bump(u8): The canonical bump seed that places the derived address off the ed25519 elliptic curve.
Rent Exemption
Registering a tag deposits a small amount of SOL (approx. 0.0016 SOL) to cover the account's rent-exempt storage fee. This SOL remains stored in the tag's PDA account on-chain.
By default the owner's wallet pays this deposit. The register_tag instruction accepts a separate payer account, decoupled from owner, so a sponsor can cover it on the owner's behalf instead; owner is still recorded as the tag's controller regardless of who paid. See Registering a Tag for the sponsored flow.