Mintvelocity

SDK

Write a hook

A hook is an ordinary Solana program. The hook crate is the whole interface: the callbacks, their arguments, the answer and the registry.

Callbacks

Implement the ones you need, each as an instruction of your program named after it. The caller invokes it by CPI with Anchor’s discriminator for that name and Borsh arguments (TokenHookArgs, PoolHookArgs).

Token hook: before_transfer after_transfer before_mint after_mint before_burn after_burn
Pool hook: before_initialize after_initialize before_add_liquidity after_add_liquidity before_remove_liquidity after_remove_liquidity before_swap after_swap

The first account is the caller’s signer, PDA(["hook-authority", your_program], caller). Accept only that one (hook_signer in the crate gives it): a signer another hook received and passes on vouches for nothing.

The answer

A before_* callback, and a pool’s after_swap, returns a HookReturn. The caller checks it and applies it: at most three cuts, never more than the amount, each to a writable holding your hook named among its extras.

pub struct HookReturn { deltas: Vec<Delta>, burn: u64, lp_fee_bps: Option<u16>, source_hook_data: Option<[u8; 64]>, destination_hook_data: Option<[u8; 64]> }

Flags

A mint’s flags say which token callbacks run and what they may answer; a pool’s, the same for pool callbacks. A field a callback may not fill refuses the whole answer (UnsupportedHookReturn).

BEFORE_TRANSFER = 1 AFTER_TRANSFER = 2 BEFORE_MINT = 4 AFTER_MINT = 8 BEFORE_BURN = 16 AFTER_BURN = 32 TRANSFER_RETURNS_DELTA = 64 WRITES_HOOK_DATA = 128

Extra accounts

Five fixed accounts come first. Anything else your hook needs goes in a registry at PDA(["bordrless-hook-accounts", mint-or-pool], your_program): fixed keys, and PDAs whose seeds may be literals, accounts already in the list, or the owners of the two holdings. write_registry creates it; the SDK resolves it (fetchTokenHook, resolveHookAccounts).

Naming and locking it

A mint names its hook at creation (hook_program, hook_flags in create_mint). While it keeps a hook authority, set_hook changes either; revoking that authority with set_authority fixes which program runs, as every kit launch is made.

Deploying it

Two lanes. Through the Workshop you deploy nothing: you submit the source, the Workshop checks it, deploys it under its own upgrade key and lists it. Or deploy it yourself like any Solana program and make it immutable (or put it behind the public hook timelock, 3 days or more): the launch program refuses a config naming a hook anyone else can upgrade. Then prepare it for the mint (templateHook.prepare for a hook on the template) and make its config on the launchpad.

solana program set-upgrade-authority <PROGRAM_ID> --final

Example: tax_hook

The tax hook is a token hook with one callback. install records the fee and the cap, publishes the registry and sets the mint’s hook to itself; prepare does the same for a mint that does not exist yet, so a launch can create it with the hook. before_transfer answers one cut to the collector and refuses a transfer that would leave a wallet over the cap. The collector is exempt, and the fee is 0 until its holding exists.

Example: the kit

The kit is the full example: a token hook whose 64 bytes do the holder accounting, installed by the launchpad, itself a pool hook. The SDK’s kitTokenHook, kitHookSlice and launch.swap show how a client carries a hook with several extras. The docs walk through both: the kit, the launchpad hook.