Protocol
64 bytes in every holding
Every holding carries 64 bytes that belong to its mint’s hook, written by the token program with the balances: no extra account per holder, nothing to create or fund first.
Who writes them
Holding.hook_data: [u8; 64] sits after frozen. Only the mint’s hook program can change it, and only when the mint has WRITES_HOOK_DATA:
by answering source_hook_data or destination_hook_data from before_transfer, before_mint (the destination) or before_burn (the source); the token program writes it with the balances, after the operation; or by calling write_hook_data(data), signed by its own ["hook-authority"] PDA at the canonical bump. It calls no hook. The kit’s claim uses it.
Closing a holding
close_holding refuses a holding whose data is not all zero when the mint’s hook has WRITES_HOOK_DATA (HookDataNotEmpty), so a record of what a holder is owed can’t vanish with the account. Without a hook or the flag nobody can ever clear the data, so the holding closes regardless.
The kit’s layout
The protocol says nothing about what is in the bytes. This is how the kit lays them out in every holding of its tokens, little-endian:
| Bytes | Type | Field |
|---|---|---|
| 0-15 | u128 | snapshot - holder rewards: acc_per_share at the holder’s last settle |
| 16-23 | u64 | owed - holder rewards: rewards earned and not claimed, in lamports |
| 24-31 | u64 | early_locked - early lock: tokens bought in the early window |
| 32-63 | - | reserved, zero |
All zero for a holding the kit has never written, and written back as all zero whenever nothing is left to keep, so the holding can close.