Skip to main content

ZkPadFactory

Source: contracts/src/ZkPadFactory.sol · Interface: IZkPadFactory · Port of Clanker v4 Clanker to PancakeSwap Infinity. Ownable2Step, ReentrancyGuardTransient.

Purpose​

One call, deployToken, launches a coin:

  1. deploys a ZkPadToken with CREATE2, salt keccak256(abi.encode(msg.sender, tokenConfig.salt));
  2. has an enabled hook create the dynamic-fee CL pool against an allow-listed quote token;
  3. has an enabled locker place 100% of the supply in 1..7 single-sided positions;
  4. optionally performs an atomic dev buy;
  5. optionally arms the anti-sniper MEV module.

It also receives the hook's protocol fees (25% of F) and the locker's protocol top-ups, and forwards them to teamFeeRecipient. The FeeVault reads tokenDeploymentInfo to authorize creator-triggered consolidations and to record launch credit.

Launch configuration​

struct DeploymentConfig {
TokenConfig tokenConfig;
PoolConfig poolConfig;
LockerConfig lockerConfig;
MevModuleConfig mevModuleConfig;
DevBuyConfig devBuyConfig;
bytes beneficiaryHint; // emitted in TokenLaunched, never stored
}
StructFieldMeaning
TokenConfigtokenAdminCosmetic admin and the only address that may lower fees; address(0) renounces both
name, symbolERC20 name and symbol
saltUser salt; mixed with msg.sender for CREATE2 (stops address squatting, not mempool observation)
image, metadata, contextCosmetic data; context is immutable (e.g. client identifier)
PoolConfighookMust be enabled via setHook
pairedTokenQuote token; must be enabled via setQuoteToken
tickIfToken0IsTokenStarting tick in token0 orientation; multiple of 200, inside the quote's bounds
tickSpacingMust equal TICK_SPACING (200)
poolDataabi.encode(IZkPadHook.PoolStaticConfigVars{tokenFee, pairedFee})
LockerConfiglockerMust be enabled for the hook via setLocker
beneficiaryIdNon-zero FeeVault id that receives 100% of LP fees
tickLower[], tickUpper[], positionBps[]1..7 positions (token0 orientation), bps sum to 10,000, each > 0
lockerDataabi.encode(ILpLocker.LpFeeConversionInfo); empty = FeeIn.Paired (convert token-side fees to the paired token). Both / Token credit the beneficiary in the launched token, which relayers cannot price and consolidation cannot route (self-funded claims only); the SDK requires allowSelfFundedTokenFees for them
MevModuleConfigmevModule, mevModuleDataaddress(0) disables; data = abi.encode(FeeConfig) for the descending-fee module
DevBuyConfigamountInPaired-token amount; for WBNB must equal msg.value; 0 = none
minAmountOutSlippage guard
recipientReceives the bought tokens (non-zero if amountIn > 0)

Functions​

FunctionAccessDescription
deployToken(DeploymentConfig) payable returns (address)anyoneLaunch. Reverts if deprecated.
claimTeamFees(address token)anyoneForward the factory's balance of token (hook protocol fees) to teamFeeRecipient
predictTokenAddress(address deployer, TokenConfig) viewCREATE2 address a launch would get
tokenDeploymentInfo(address token) viewDeploymentInfo{token, hook, locker, mevModule, pairedToken, poolId, beneficiaryId, deployer, launchedAt}
quoteTokenConfig(address) viewQuoteTokenConfig{enabled, minStartingTick, maxStartingTick}
launchOf(address token) view returns (address creator, bytes32 beneficiaryId)Creator (msg.sender of deployToken) and beneficiary id; used to authorize creator-triggered consolidation
launchCount() view, launchAt(uint256 index) viewBounded global launch index, in launch order
enabledHooks, enabledLockers(locker, hook), enabledMevModulesviewAllow-lists
admins(address) viewWhether an address may manage quote tokens
TOKEN_SUPPLY, TICK_SPACING, vault, poolManager, wbnb, deprecated, teamFeeRecipientviewConfiguration
setDeprecated(bool)ownerStop (or resume) new launches; never affects existing ones
setHook, setLocker, setMevModuleownerEnable or disable components for new launches
setAdmin(address admin, bool enabled)ownerGrant or revoke the quote-token admin role (e.g. the QuoteRegistry, which admits Tier 2 quotes). Clanker v4 OwnerAdmins.
setQuoteToken(address, QuoteTokenConfig)owner or adminAllow-list a quote with tick bounds; disabling stops only new launches
setTeamFeeRecipient(address)ownerTreasury for protocol fees

Events​

EventEmitted when
TokenLaunched(msgSender, tokenAddress, tokenAdmin, pairedToken, poolId, beneficiaryId, beneficiaryHint, tokenName, tokenSymbol, tokenImage, tokenMetadata, tokenContext, startingTick, poolHook, locker, mevModule, devBuyAmountIn, devBuyAmountOut)A launch succeeds. Indexed: tokenAddress, tokenAdmin, pairedToken.
DevBuy(token, recipient, amountIn, amountOut)A dev buy executes
ClaimTeamFees(token, recipient, amount)Protocol fees are forwarded
SetDeprecated, SetHook, SetLocker, SetMevModule, SetAdmin, SetQuoteToken, SetTeamFeeRecipientAdmin changes

Errors​

Deprecated, ZeroAddress, InvalidHook, InvalidLocker, InvalidMevModule, HookNotEnabled, LockerNotEnabled, MevModuleNotEnabled, QuoteTokenNotAllowed(quote), InvalidTickBounds, InvalidStartingTick(tick), InvalidTickSpacing(tickSpacing), InvalidMsgValue, InvalidDevBuy, DevBuySlippage(amountOut, minAmountOut), TeamFeeRecipientNotSet, OnlyVault, SupplyNotPlaced, Unauthorized, IndexOutOfBounds(index, count).

Notes​

  • msg.value is accepted only as the dev buy of a WBNB-paired launch, and must equal devBuyConfig.amountIn.
  • Pool pre-initialization is impossible: only the hook can initialize zk-pad pools, and it does so only for the factory.
  • Use the SDK's buildLaunchParams to assemble and validate a DeploymentConfig.