Stoke
Hooks

Plugins for a pool.

A hook is a small program attached to a pool. The pool calls it at set moments, before and after trades and deposits, and it can change what happens: the fee, the price, who may trade. It's Uniswap v4's design, and Stoke runs it on Solana. Every coin launched here is a pool with one hook, Stoke Launch, which runs its curve and its fees.

Look up any hook

Paste a hook's address and see, in plain words, what it can do to traders and liquidity providers.

Design your own

Pick what it does, get a program address that carries exactly those permissions, and a code template.

Then a developer builds it

They fill in the template and deploy it, and pools on Stoke's PoolManager can use it. Launching a coin with your own hook from this site isn't available yet.

Launching or trading coins? You don't need anything on this page: every coin already uses Stoke Launch. This is for developers.

Liveprotocol/programs/launch_hook

Stoke Launch: the hook every coin uses

The way launchpads are built on v4 (Doppler, Flaunch, Zora): each launch is a pool whose hook fills every swap from a bonding curve. When a buy sells the curve's last token, the hook queues adding the curve's SOL and the reserved tokens as the pool's liquidity, and the rest of that same buy fills from the pool. No migration, no second pool, nothing to snipe in between.

  • Approve new pools
  • Approve deposits
  • Run before every trade
  • Run after every trade
  • Fill trades itself
  • Take a cut of trades
Graduates in the swap

The completing buy adds the liquidity and keeps going.

Anti-snipe burns

Buys in the first second pay 90%, spent on tokens that are burned.

Liquidity locked in the hook

No instruction can remove it. Fees go to the creator, stakers and the pool.

Look up any hook

Paste a hook's address to see what it can do, what that means for you, and how many pools use it.

Design a hook

Four steps. The first three need no code; the last is for whoever writes it.

01
Start from an example

Pick what kind of hook you're making. You can change anything below.

A fee override that starts high at launch and decays to the base fee. Used by Zora, Clanker v4.

02
Choose what it does

Tick the moments your hook runs at and what it may change. Pools can see this list, so ask only for what you need.

Trades
Moving money
Deposits and withdrawals
New pools
Tips to liquidity providers
Traders and liquidity providers would see:Allowed
  • · Runs on every swap: can refuse trades or change the fee.
03
Get its address

On Uniswap v4 and here, what a hook may do is written into its address, so nobody can change it later. Your browser tries random keys until it finds one whose address matches your choices.

Technical: permission flags 0x1080, the last 14 bits of the address.

04
Write the logic

For a developer: a Rust (Anchor) template with exactly the callbacks you picked. Fill them in, deploy with the keypair, and pools can use it.

Show the code template
use anchor_lang::prelude::*;
use meridian_core::*;

// Mined so its last 14 bits encode this hook's permissions (0x1080).
declare_id!("<mined program id>");

#[program]
pub mod my_hook {
    use super::*;

    /// Runs once a pool exists, e.g. to set its starting fee.
    pub fn after_initialize(ctx: Context<HookCall>, _sender: Pubkey, _key: PoolKey, _sqrt_price: u128, _tick: i32) -> Result<HookEffects> {
        let _pool = verify_call(&crate::ID, &ctx.accounts.caller, &ctx.accounts.pool)?;
        Ok(HookEffects::default())
    }

    /// Can block a trade or change its fee.
    pub fn before_swap(ctx: Context<HookCall>, _sender: Pubkey, _key: PoolKey, _params: SwapParams, _hook_data: Vec<u8>) -> Result<BeforeSwapReturn> {
        let _pool = verify_call(&crate::ID, &ctx.accounts.caller, &ctx.accounts.pool)?;
        Ok(BeforeSwapReturn::default())
    }
}

/// The PoolManager calls every callback with [hook_caller (signer), pool, ...remaining].
#[derive(Accounts)]
pub struct HookCall<'info> {
    /// The PoolManager's per-pool signer; verify_call checks it.
    pub caller: Signer<'info>,
    /// CHECK: verified by verify_call (owner, discriminator, and that its hook is this program).
    pub pool: UncheckedAccount<'info>,
}
For developers

How Uniswap v4 maps to Solana

Same capabilities. Where Solana works differently, here is what replaces what.

PoolManager singleton: every pool in one contract
One PoolManager program; every pool is a PDA of its key (currencies, fee, tick spacing, hook). Vaults are per pool so pools trade in parallel.
Hook permissions in the hook's address bits
The same 14 bits, in the hook program id's last two bytes. Mine a keypair for them (above) and the program's permissions are fixed for good.
onlyPoolManager
Each pool has a PoolManager signer PDA that signs only its hook calls; verify_call checks it, the pool, and that the pool's hook is you.
beforeSwap → BeforeSwapDelta, afterSwap → int128
Identical sign conventions and rules, including HookDeltaExceedsSwapAmount. A delta returned without its permission is ignored, as in v4.
take / settle / mint / burn inside callbacks
Solana forbids re-entering a caller, so a hook's deltas settle against its claims (ERC-6909-style) when the operation ends. Tokens a hook moves into a vault mid-callback are credited to it, like settle().
Calling modifyLiquidity / swap / donate from a callback
Return them as actions: the PoolManager runs them as the hook right after the callback, before it continues, which is where a v4 nested call would land. JIT liquidity, limit orders and in-swap graduation all work this way.
updateDynamicLPFee, lpFeeOverride
Both: a hook returns a fee update from any callback (or calls the instruction itself), and beforeSwap can override the fee for one swap with OVERRIDE_FEE_FLAG.
noSelfCall
Operations the hook signs itself (its PDA ["hook"]) skip its own callbacks.
hookData
Passed through to every callback, byte for byte.
Flash accounting across unlock()
Each instruction settles its own deltas; chain several instructions in one transaction, which is atomic, to compose.