Building a v4 hook? Pick what it does, set the numbers, and deploy it as your own hook or stacked on v4 Marketplace. Open the builder ↗
v4 Builder docs
Build a v4 hook from modules

Deploying and fees

Every hook built here is deployed through the v4 Builder factory, from your own wallet. The factory places the code at its CREATE2 address, checks it, records the recipe it was written from, and passes the deploy fee on to the $V4B stakers.

The deploy call

The builder sends one transaction from your wallet to the factory at 0x227a41C9b869f7cE396337C88ffd0226917aBF4a: the creation code with its constructor arguments, a mined salt, the kind (0 for an own v4 hook, 1 for a stacked hook) and the recipe string.

BuilderFactory
function deploy(bytes calldata initCode, bytes32 salt, uint8 kind, string calldata recipe)
    external
    payable
    returns (address hook);

/// The salt CREATE2 actually uses.
function effectiveSalt(address builder, bytes32 salt) public pure returns (bytes32) {
    return keccak256(abi.encode(builder, salt));
}

/// What `builder` pays for one deploy right now.
function priceFor(address builder) public view returns (uint256);

A salt bound to the sender

CREATE2 does not use the salt you send: it uses keccak256(abi.encode(sender, salt)). A deploy seen in the mempool cannot be copied by another wallet to take the address, because from any other sender the same salt lands somewhere else. This is also why the builder mines the salt for the wallet you connect, and why addressOf(builder, salt, initCodeHash) gives the address before you send anything.

What the factory checks

  • The payment is exactly priceFor(sender), or the call reverts with WrongPayment(expected).
  • For an own v4 hook, the low 14 bits of the new address must equal the permissions the code declares in getHookPermissions(), or the deploy reverts with BadPermissions(declared, address_). A return-delta permission without the call it rides on is refused too, since such a hook could never open a pool.
  • A failed creation reverts with DeployFailed(reason), carrying the constructor's own revert data.

What it records

Each hook gets a record in built(hook): the builder, the time, the kind, the flags and keccak256 of the recipe. The full recipe string goes into the Built event, so anyone can rebuild the exact source from the event alone. See rebuilding a hook.

The Built event
event Built(
    address indexed hook,
    address indexed builder,
    uint8 indexed kind,
    uint16 flags,
    bytes32 recipeHash,
    string recipe,
    uint256 paid
);

The fee

A deploy0.0003 ETH, flat, whatever the hook
HoldersWallets holding at least 1,000,000 $V4B deploy for free: priceFor returns 0
Where it goesForwarded in the same transaction to the $V4B stakers' distributor
Before the distributor is setFees wait in the factory; anyone can call forward() once it is
CeilingThe factory refuses any fee above 0.01 ETH: MAX_FEE in its code

$V4B is the token of v4 Builder. Staking it earns the deploy fees of every hook built here. The balance for the free tier is read on chain at deploy time; a balance call that fails counts as no balance, so the deploy is simply priced at the fee.

The factory's owner can change the fee under that 0.01 ETH ceiling, the free-tier threshold and the address fees are forwarded to; the token is set once and cannot be changed after. Ownership moves in two steps: a transfer, then an accept from the new owner.

After the deploy

  • An own v4 hook: open a pool with it. If it sets fees, the pool takes the dynamic fee flag 0x800000; if not, the recipe's base fee is the pool's fee. The builder opens it and adds a first full-range position from your wallet in one PositionManager call.
  • A stacked hook: list it on v4 Marketplace. See listing.
  • Either way, the builder publishes the source on Sourcify right after the deploy, from the recipe on chain, so the explorer shows verified code. The verify endpoint that does it works for any hook built through the factory.