Compose your own policy
Combine timing, membership, fees, and rewards inside one hook without adding rules to the AMM.
The core supplies authenticated facts and bounded execution tools. A hook author decides what those facts mean. A pool can remain permissionless, require a proof, apply a time-dependent fee, or award a separate reward asset. None of those policies is a default pool restriction.
One hook, several decisions
Suppose a market should open at a given time, accept members during an early window, decay its input fee, and issue credits after purchases. Implement those decisions in one hook program with its own configuration.
| Phase | Read from the core | Developer-defined decision |
|---|---|---|
| BeforeInitialize | Pool, mints, creator, configuration snapshot | Accept the intended market and policy configuration |
| BeforeSwap | Actor, direction, mode, request limits, frozen Clock | Enforce the time window, verify membership, choose a fee |
| AfterSwap | Actual consumed input, net output, output fee, resulting state | Award credits using the amount actually settled |
| BeforeAddLiquidity | Position and signed liquidity intent, pool mode | Decide whether this liquidity operation is permitted |
| AfterAddLiquidity | Resulting liquidity and principal amounts | Update permitted hook-owned accounting |
This is a policy design, not a new built-in composite instruction. Use the separate examples as building blocks and write tests for the combined behavior.
- BeforeSwapAuthenticate · check eligibility · choose permitted fees
- Core settlementPrice · user limits · reserve transfers
- AfterSwapRead actual amounts · apply declared effects
Order the checks deliberately
Reject invalid context and accounts before running an expensive proof or external CPI. Check cheap eligibility rules before preparing sponsored accounts. Calculate bounded replies only after the operation is eligible. Mint rewards only from authenticated settled amounts.
authenticate core callback and pool binding
→ validate hook state and declared external accounts
→ check time and membership rules
→ choose an allowed fee
→ let the core settle
→ calculate reward from actual outputAfterSwap remains inside the transaction. If reward issuance is mandatory and fails, the trade rolls back. If the product intends optional rewards, define and test an explicit policy for when it may return success without issuance; never silently change that promise in an adapter.
Use the right identity
The core authenticates the swap actor and token-account relationships. The hook receives that context without receiving the actor's wallet signature as a general-purpose CPI capability. Actor identity is not proof that an account is the original human at the beginning of every routed transaction.
An allowlist proof proves membership against the configured root. The whole address list is not stored in each proof. Bind the leaf to the intended actor and policy domain; do not accept a caller-selected address merely because its proof is valid.
Scope each permission
Declare only the accounts and writable phases the policy needs. A reward issuer may need writable mint and recipient state after settlement; a timing check can remain read-only. Account descriptors select roles within the pool's immutable permission ceiling. They do not grant reserve custody or arbitrary signing power.
See permissions for ActorReadOnly, CreatableHookState, and PoolMintReadOnly; rewards demonstrates sponsored preparation and external token-program calls.
Quote the same policy
For a public Metis quote, the hook adapter needs enough public state to produce the same financial result as execution. A Clock-based decay can use a coherent snapshot; a buyer-specific proof cannot be guessed before the buyer is known.
Keep quote logic alongside the example policy, inject it into the generic adapter, and validate the policy again on-chain. A supported quote adapter cannot bypass an on-chain denial. Read Metis compatibility before promising a custom hook can participate in every route.
Test the combination
Cover opening/closing timestamps, invalid proofs, both swap directions and modes, fee caps, insufficient sponsorship, capped rewards, account substitution, and rollback after a later callback fails. For a curve, include graduation with pool_mode changing from 1 to 0. For zaps, verify both callback sequences and the final user limit.
Use hook validation to check combined effects and rollback. Each standalone rule must also remain correct when composed.