Security

A module runs inside the swap, but it is bounded by it. What a module can and cannot do, the checks the AMM makes on every call, and the risks that remain.

What a module cannot do#

Touch the vaults
Vault authority is the pool PDA, and the AMM never passes it to a module as a signer. The hook authority it does sign with owns nothing.
Use your signature
Every account forwarded to a module has is_signer = false. The user, the payer and the pool never sign for a module.
Pose as another module
Each module of a pool has its own hook authority, ["hook_auth", pool, module], and the AMM signs for exactly one per call.
Re-enter the pool
Solana forbids A → B → A calls, so a module cannot call back into the AMM in the middle of a swap.
Break min-out
The user receives at least min_amount_out, or the whole transaction reverts.
Change the rules later
The patch is part of the pool’s address and can never change. Built-in module params are fixed at creation.
Exceed its jacks
The AMM calls only the hook points whose bits are set, and ignores fee overrides and deltas from modules without the matching bit.

What a module can do#

Revert
Any module can make the instruction it is called in fail. A module with Before remove can refuse withdrawals: that is how Lockup works, and it is also what a hostile module would do.
Raise the fee
With Dynamic fee, up to 50% for that swap.
Trade next to you
With Returns delta, take part of the remaining input before the curve, or run its own curve trades after it. It must deposit first; the user is protected by min_amount_out.
Read the swap
Sender, direction, amounts, reserves, fee and timestamp are passed to it.
Spend compute
Its calls count toward the transaction’s compute budget.

Checks on every module call#

CheckWhat it prevents
slice[0], slice[1], slice[2] equal the program, module and hook authority stored in the poolThe caller cannot swap in a different program or authority.
Signs only with the ["hook_auth", pool, module] seedsThe module gets a signature that is good for itself and nothing else.
is_signer = false on every forwarded accountNo user, payer or pool signature ever reaches a module.
Return data used only if the module program set it; malformed data failsAnother program cannot answer on a module’s behalf.
Fee override at most 5000 bps, and only with Dynamic feeThe fee has a hard ceiling of 50%.
take_in at most the remaining input, recipient index ≥ 3A module takes only what it reported, into its own accounts.
give_out and trade inputs checked by vault balance differenceA module is paid only for tokens it actually deposited.
No vault balance may decrease during a module callNothing leaves the vaults except through the AMM’s own transfers.
At most 4 hook trades, each with out ≥ min_outBounded work, no surprise prices.
vault ≥ reserve + protocol fees, both sides, after every instructionAccounting can never claim more than the vaults hold.
Checked u128 math, rounding in the pool’s favourNo overflow, no rounding drain.

Checks at pool creation#

  • At most four modules, all distinct.
  • Each module account is owned by its program, the program is executable, and the module account is not itself a program.
  • The Patchbay program cannot be a module program.
  • Every module’s flags are valid.
  • fee_bps is at most 1000; the mints are different and ordered.
  • Token-2022 mints carry only allowed extensions: no transfer fees, transfer hooks, permanent delegates or other extensions that change how transfers behave. The check runs again on the first deposit.

What the admin can and cannot do#

One admin key manages the global config. initialize_config can only be signed by the AMM program’s upgrade authority, so nobody can claim the admin role between deployment and setup. The admin can:

  • set the treasury and the protocol’s share of the LP fee, at most 25%;
  • list or unlist modules in the registry;
  • send a pool’s accrued protocol fees to the treasury;
  • hand the admin role to another key, in two steps (propose, then accept).

It cannot change a pool’s fee or patch, move reserves or LP funds, or pause swaps. The registry gates nothing on-chain: it only decides which modules the app shows by name.

Risks#

For liquidity providers#

  • A pool is only as safe as its modules. Read every module in the patch before you deposit: a Before remove module can keep you in, and a Returns delta module trades against the pool.
  • A Lockup locks the whole pool until its unlock time, including liquidity added later.
  • Impermanent loss, as in any constant-product pool.

For traders#

  • Always set a minimum output. The app and the SDK do; it is your protection against a fee change or a hostile module.
  • A dynamic fee can change between your quote and your transaction.

For everyone#

  • Patchbay v1 is new software. No audit report is published yet; this page will link one when it is.
  • A listing in the registry is not an audit.