procedure
the tame program instructions, in execution order.
initialize pool (initialize_pool)
Fires once, after the bound Whirlpool exists. Stores the Whirlpool address, the tame mint, and the geometry constants in the binding PDA. All subsequent hook invocations validate their incoming Whirlpool against this PDA. Transfers routed through any other pool revert at the entrypoint.
The instruction also enforces the pool’s geometry. token_a must be wSOL. token_b must be the tame mint. fee_tier must be zero, since tame’s economic logic operates entirely outside the standard fee-tier mechanism. tick_spacing is fixed at 64 to constrain the resolution at which liquidity can be placed. Any pool failing these constraints reverts before initialization completes.
initialize extra account meta list (initialize_extra_account_meta_list)
Writes the ExtraAccountMetaList PDA that Token-2022 reads to know which accounts the hook requires at execute time. Called once after initialize_pool. The list encodes the binding PDA, the coefficient state account, the Whirlpool, and the tickArray accounts within the walk window.
The Token-2022 program validates this list before invoking the hook. A malformed or incomplete list causes the entire transfer to fail at the program boundary, before any tame logic runs. The binding between the token, its hook program, and the bound pool is enforced by the runtime, not by trust.
transfer hook execute, swap path (transfer_hook_execute)
Fires on every tame token transfer the Whirlpool emits during a swap. Reads sqrt_price and active tick from the Whirlpool state account. Walks tick liquidity in the ±3 tickArray window around the active tick.
For each populated tick within the window, it reads the tick’s net liquidity via the Whirlpool’s tick account. Each contribution is weighted by inverse distance from the active tick (closer ticks count more, farther ticks count less). The weighted sum is normalized by total pool liquidity to produce a unitless value between zero and one. This is the creature’s tameness.
The hook does not modify the swap or charge a fee. It exists to record state. The recomputed coefficient is written to the protocol’s state account as 9-decimal fixed-point. cumulative_swap_count is incremented. CoefficientUpdated is emitted as an Anchor event for off-chain indexers.
transfer hook execute, position-open path (transfer_hook_execute)
Same entrypoint as the swap path, dispatched on the transfer direction and source. When the source is the LP and the destination is the pool vault, the hook is opening or increasing a position.
It reads the position’s tick_lower and tick_upper from the position account, computes max_allowable_tick_width = MAX_TICK_RANGE × (1 − coefficient), and reverts with TameError::RangeExceedsAllowable if the range exceeds it. At coefficient zero, the creature is feral and any range is acceptable. At coefficient near one, only positions within ±tick_spacing of the active tick are accepted.
The gate is not advisory. There is no penalty path, no fee, and no graceful degradation. The entire instruction including the token transfer simply does not complete. Late LPs cannot fight the trend, only follow it.
transfer hook execute, position-close path (transfer_hook_execute)
When the source is the pool vault and the destination is the LP, the hook is closing or decreasing a position. Unlike the deposit gate, it does not reject the operation. Instead, it computes a coefficient adjustment proportional to the withdrawn liquidity’s distance from the active tick.
Withdrawals from concentrated bands (positions tightly clustered around the active price) produce smaller coefficient decreases than withdrawals from wide bands. This asymmetry is intentional. It preserves the work done by past swaps; the geometry the pool has been steered into is sticky against random LP exits.
Positions far from the active tick contribute less to the coefficient, so removing them costs less. Positions at the active tick contribute the most, so removing them is the only mechanism that meaningfully relaxes the geometry. The geometry resists dilution. CoefficientUpdated is emitted.