Skip to content

Integrating as a launcher

Open pools from your launchpad on a hook of your own: the launch call, who may open pools, accepting ownership, integrators and arb recapture.

On this page

A launcher is a launchpad, an app or a contract that opens Hookr pools for its own users. It opens them through HookrLauncher, either on Hookr's hook or on a hook of its own: the Hook Blocks it composes in the Builder, deployed at an address it owns. This guide covers the second path, the one a launchpad plugs in.

Opening pools through HookrLauncher is route C under Listing Tiers: the contracts set Hookr's share, so there is nothing to negotiate and nothing extra to read back. A launcher that runs a hook Hookr did not deploy is listed on route A or route B instead.

Your own hook in four steps

  1. Compose. Place the Hook Blocks you want in the Builder and save them as a saved hook.
  2. Deploy. Deploy a hook of your own from the saved hook through HookrOwnedRootFactory. You choose the features the hook advertises (ruleMask), within the saved hook's, whether it opens pools for everyone or for its owner alone, and its owner. The call carries exactly the factory's deployFee(); Owned roots shows it as read from chain.
  3. Own. Name your launchpad's wallet or contract as the owner. An owner other than the wallet that deploys accepts the role first: see Accepting ownership.
  4. Plug in. Your launchpad calls HookrLauncher.launch(token, hook, members, deadline), with your hook's address as the root.

launchAdvised, launchWithBuy and launchFamily take the root the same way, and HookrLauncher checks the hook the same way for each of them.

Your contract is the caller

HookrLauncher acts on its caller, msg.sender. When your launchpad's contract makes the call, three things follow.

It is the opener. The registry decides whether the caller may open pools on the hook. On an owner-only hook, only the owner gets a yes, so the contract that calls must be the owner.

It owns the launch's positions. The pools one launch opens are a family, and the family belongs to the caller (familyOwner(familyId)). Only the family's owner withdraws its liquidity, and it hands the family on in two steps, transferFamily then acceptFamily.

It is a new token's creator. A new token's address depends on who launches it. predictToken(yourContract, token) returns that address before the launch.

Each pool on your hook binds the hook's own copy of the core blocks: the module the factory names with rulesOf(hook), the one core module admitted on it. Hookr's own is not admitted there.

Who may open pools on your hook

HookrLauncher asks the registry rootOpenFor(hook, msg.sender) before every launch and reverts InvalidFamily() on a no.

  • Owner-only. Only the hook's owner opens pools on it. Its ruleMask may leave out any of the saved hook's features.
  • Public. Anyone opens pools on it. A public hook must allow Anti-Snipe, dynamic fees, LP Rewards and the creator royalty, a ruleMask that includes 27; only Auto Burn may be left out. A public deploy that leaves out more reverts SoftMaskNeedsOwnerOnly.
  • Paused. While the owner pauses the hook (setPaused(hook, true) on the factory), it opens no new pools for anyone. Pools already open keep trading.

Of the features a ruleMask leaves out, only Auto Burn is enforced when a pool opens: a pool that asks for a burn fails to open. Anti-Snipe, dynamic fees, LP Rewards and the royalty are checked when a pool joins a saved hook (adoptPool, and the factory's ownedRootConforms), not at launch, so a pool on an owner-only hook can still open with them.

The registry also answers no for every caller while the hook is closed or new pools are paused across Hookr. Read rootOpenFor before you build a launch, and show your user the reason rather than retry.

Accepting ownership

The owner named at deploy holds the role at once only when it is the wallet that deploys. Any other owner, such as your launchpad's contract, is only the pending owner until it calls acceptRootOwnership(hook) on the factory.

Until it accepts, the hook has no owner: an owner-only hook opens no pools for anyone, and nobody can pause it or hand it on. pendingRootOwner(hook) reads who may accept. A contract owner therefore needs a way to make that call, and the same goes for setPaused and transferRootOwnership if it should ever pause the hook or hand it on.

Handing the role on later takes the same two steps: the owner calls transferRootOwnership(hook, next), and next calls acceptRootOwnership(hook).

Naming an integrator

A pool can name an integrator in its core block settings (RulesConfig.integrator): an account paid a part of Hookr's share of the pool's block fees, at the rate Hookr's treasury lists for it. See Integrators for the rates.

Listing is a decision of Hookr's treasury. This list is only about who may be named as an integrator, and it is separate from Listing Tiers, which cover listing a hook. Its owner proposes an account and a rate (proposeIntegrator) and accepts it after a delay (acceptIntegrator). There is no application flow in the contracts, so ask through a partner review.

  • It works the same on your own hook: its core blocks pay Hookr's treasury and read the treasury's list.
  • A pool that names an account the treasury does not list fails to open; its core module refuses it with UnknownIntegrator.
  • A pool keeps the integrator and rate it opened with. A change to the list reaches only pools opened after it.
  • The integrator collects its credit by calling claim on the pool's core module, so it must be an account that can make that call: a wallet, a Safe, or a contract that calls claim.

Arb recapture on your own hook

Your hook starts without arb recapture. Its copy of the lane is off, activeLaneOf(hook) on the registry names no executor, and a launch with any member asking for arb recapture (recapture.on) reverts InvalidConfig(). Launch every member with it off.

Hookr opens a hook's lane itself, with an executor that serves every registered hook. Only pools opened after that take arb recapture: a pool fixes its terms when it opens, so one opened before keeps none.

Reverts to surface

RevertMeaning
InvalidFamily()The registry said no to this caller on this hook: not the owner of an owner-only hook, the hook paused or closed, or new pools paused. Also a passed deadline, or members the launcher cannot take
NotRootOwner(hook, caller)acceptRootOwnership from an account that is not the pending owner, or setPaused or transferRootOwnership from one that is not the owner
SoftMaskNeedsOwnerOnly(ruleMask)A public deploy that leaves out more than Auto Burn
InvalidOwner()A deploy that names the zero address as owner
WrongFee(sent, fee)A deploy whose value is not exactly deployFee()
NotProfileOwner(profileId, caller)A deploy from an owner-only saved hook the caller does not own
PoolExists(member, poolId)That member's pool is already open
InvalidConfig()A member asks for arb recapture (recapture.on) while the hook's lane is off, or the hook refuses a member's pool settings
OutsideProfile(profileId)A deploy whose ruleMask goes beyond the saved hook's
ProfileVersionMismatch(profileId, selected, current)The saved hook changed after the deploy read it: read its version again
SaltUsed(deployer, salt)The deploying wallet already used that salt: pick another
FactoryFull(cap)The factory has reached its cap on hooks

Next steps

Read Owned roots for everything a hook of your own does, and Launch on your own hook for encoding the launch with the SDK's ABI: its launch builders take only HookrRoot.