Overview

Invite-gated token launches on Uniswap v4. Creators open a Continuous Clearing Auction (CCA); after graduation, proceeds seed a locked v4 pool. This repo adds invite validation and hook-based fee distribution on top of Uniswap’s Liquidity Launchpad.

Mechanics

Launches use Uniswap’s CCA: bidders set a budget and max price; each block, a release schedule allocates tokens to active bids at a uniform clearing price. Early participation is rewarded and last-minute sniping is ineffective — see the CCA overview and whitepaper.

Flow in this stack:

  1. LaunchCcaLaunchFactory mints a fixed-supply LaunchToken, seeds invite codes, and opens a CCA via LiquidityLauncher → LBPStrategy.
  2. Bid — Participants submitBid with invite hookData, checked by InviteValidationHook / InviteRegistry (referral weight is recorded for later fee claims).
  3. Migrate — After the auction ends, anyone can call LBP migrate to seed an ETH/token v4 pool at the discovered price, with LaunchFeeHook attached.
  4. Trade & claim — Swaps accrue hook fees; harvest pushes balances to FeeDistributor for creator / referrer / platform claims. Auction winners claim tokens after the configured claim block.

Fees

Defaults (overridable at launch where noted):

ParameterDefaultNotes
Token split50% auction / 50% LPauctionSupplyBps; remainder reserved for the post-migrate position
Pool LP fee0.1%Accrues to the locked LP NFT; autocompounded back into the pool via CompoundingClaimRecipient
Hook fee0.4%Taken by LaunchFeeHook on the unspecified swap amount (afterSwap)
Hook fee split20% creator / 75% referrers / 5% platformFixed in FeeDistributor; referrers share pro-rata by invite count

Example — $10M trading volume

Assume a $50k auction raise seeds the locked LP (default 50/50 auction/LP split).

FeeRateOn $10M volume
Pool LP fee (autocompounded)0.1%$10,000 reinvested into the position → liquidity $50k → $60k
Hook fee (distributed)0.4%$40,000 harvested into FeeDistributor

Hook fee split of that $40,000:

  • Creator claims $8,000 (20%)
  • Platform claims $2,000 (5%)
  • Referrer pool gets $30,000 (75%). Shared pro-rata across referrers by invite count — with 100 equal-weight referrers, each can claim $300.

Contracts

ContractRole
CcaLaunchFactoryCreate token + CCA/LBP launch
LaunchTokenFixed-supply ERC-20 + metadata
InviteRegistryInvite codes + referral weights
InviteValidationHookCCA bid gate (hookData)
LaunchFeeHookPost-migrate swap hook fee
FeeDistributorClaimable 20/75/5 fee split
IReferralSourceReferral weight interface

Upstream Uniswap pieces used at runtime (not in this repo’s src/): LiquidityLauncher, LBPStrategy, Continuous Clearing Auction, CompoundingClaimRecipient.

CcaLaunchFactory

Creates LaunchToken + CCA/LBP distribution with invite gating and fee hook.

Constants

DEFAULT_POOL_LP_FEE

uint24 public constant DEFAULT_POOL_LP_FEE = 1_000

DEFAULT_HOOK_FEE

uint24 public constant DEFAULT_HOOK_FEE = 4_000

DEFAULT_TICK_SPACING

int24 public constant DEFAULT_TICK_SPACING = 60

DEFAULT_AUCTION_SUPPLY_BPS

uint16 public constant DEFAULT_AUCTION_SUPPLY_BPS = 5_000

DEFAULT_AUCTION_TICK_SPACING

uint256 public constant DEFAULT_AUCTION_TICK_SPACING = 100 << FixedPoint96.RESOLUTION

DEFAULT_FLOOR_PRICE

uint256 public constant DEFAULT_FLOOR_PRICE = 1000 << FixedPoint96.RESOLUTION

launcher

ILiquidityLauncher public immutable launcher

lbpStrategy

ILBPStrategy public immutable lbpStrategy

ccaFactory

IDistributorFactory public immutable ccaFactory

invites

InviteRegistry public immutable invites

distributor

FeeDistributor public immutable distributor

feeHook

LaunchFeeHook public immutable feeHook

positionRecipient

address public immutable positionRecipient

State Variables

launchCount

uint256 public launchCount

launches

mapping(uint256 => Launch) public launches

launchIdByToken

mapping(address => uint256) public launchIdByToken

launchIdByAuction

mapping(address => uint256) public launchIdByAuction

Functions

constructor

constructor(
    ILiquidityLauncher launcher_,
    ILBPStrategy lbpStrategy_,
    IDistributorFactory ccaFactory_,
    InviteRegistry invites_,
    FeeDistributor distributor_,
    LaunchFeeHook feeHook_,
    address positionRecipient_
) ;

createLaunch

function createLaunch(CreateParams calldata params)
    external
    returns (uint256 launchId, address token, address auction);

getLaunch

function getLaunch(uint256 launchId) external view returns (Launch memory);

_buildSteps

function _buildSteps(uint64 auctionBlocks) internal pure returns (bytes memory steps);

_poolKey

function _poolKey(address currency, address token, uint24 fee, address hook)
    internal
    pure
    returns (PoolKey memory key);

Events

LaunchCreated

event LaunchCreated(
    uint256 indexed launchId,
    address indexed creator,
    address token,
    address auction,
    uint64 endBlock,
    uint128 minRaise,
    uint24 poolLpFee,
    uint24 hookFee
);

Errors

EmptyName

error EmptyName();

InvalidDuration

error InvalidDuration();

InvalidSupplyBps

error InvalidSupplyBps();

InvalidFee

error InvalidFee();

NeedInvites

error NeedInvites();

Structs

Metadata

struct Metadata {
    string name;
    string symbol;
    string description;
    string image;
    string website;
    string twitter;
    string telegram;
}

CreateParams

struct CreateParams {
    Metadata metadata;
    uint64 auctionBlocks;
    uint128 minRaise;
    uint16 auctionSupplyBps;
    uint24 poolLpFee;
    uint24 hookFee;
    bytes32 salt;
    bytes32[] inviteCodes;
}

Launch

struct Launch {
    address creator;
    address token;
    address auction;
    uint64 startBlock;
    uint64 endBlock;
    uint64 claimBlock;
    uint128 minRaise;
    uint24 poolLpFee;
    uint24 hookFee;
}

LaunchToken

Inherits: ERC20

Fixed-supply ERC-20 with immutable launch metadata.

Constants

TOTAL_SUPPLY

uint256 public constant TOTAL_SUPPLY = 1_000_000_000 ether

factory

address public immutable factory

State Variables

description

string public description

image

string public image

website

string public website

twitter

string public twitter

telegram

string public telegram

Functions

constructor

constructor(
    string memory name_,
    string memory symbol_,
    string memory description_,
    string memory image_,
    string memory website_,
    string memory twitter_,
    string memory telegram_,
    address recipient
) ERC20(name_, symbol_);

InviteRegistry

Inherits: IReferralSource

Invite codes and referral weights.

Deployed once per chain; shared across all auctions (keyed by auction address). Authority for bid gating + fee attribution (offchain DB is UX-only):

  • Factory registers each auction and seeds creator invite codes (bytes32 → issuer).
  • InviteValidationHook calls useInvite on first CCA bid; unknown/self invites revert.
  • Codes are reusable; only the first participation per bidder credits the issuer.
  • Creator or prior participants may createInvites; FeeDistributor reads referral counts.

State Variables

factory

CcaLaunchFactory — only caller allowed to registerAuction / seedInvites.

address public factory

validationHook

address public validationHook

creatorOf

mapping(address => address) public creatorOf

auctionOfToken

mapping(address => address) public auctionOfToken

inviteIssuer

mapping(address => mapping(bytes32 => address)) public inviteIssuer

participated

mapping(address => mapping(address => bool)) public participated

referralCountOf

mapping(address => mapping(address => uint256)) public referralCountOf

totalReferralCountOf

mapping(address => uint256) public totalReferralCountOf

invitesCreated

mapping(address => uint256) public invitesCreated

Functions

setFactory

function setFactory(address factory_) external;

setValidationHook

function setValidationHook(address hook_) external;

registerAuction

function registerAuction(address auction, address token, address creator) external;

seedInvites

function seedInvites(address auction, address issuer, bytes32[] calldata codes) external;

createInvites

function createInvites(address auction, bytes32[] calldata codes) external;

_createInvites

function _createInvites(address auction, address issuer, bytes32[] calldata codes) internal;

useInvite

Called by InviteValidationHook during CCA submitBid.

function useInvite(address auction, address bidder, bytes32 code) external;

referralCount

function referralCount(address auction, address referrer) external view returns (uint256);

totalReferralCount

function totalReferralCount(address auction) external view returns (uint256);

Events

FactorySet

event FactorySet(address indexed factory);

ValidationHookSet

event ValidationHookSet(address indexed hook);

AuctionRegistered

event AuctionRegistered(address indexed auction, address indexed token, address indexed creator);

InviteCreated

event InviteCreated(address indexed auction, bytes32 indexed code, address indexed issuer);

InviteUsed

event InviteUsed(address indexed auction, address indexed bidder, address indexed referrer, bytes32 code);

Errors

AlreadySet

error AlreadySet();

NotAuthorized

error NotAuthorized();

InvalidInvite

error InvalidInvite();

InviteExists

error InviteExists();

ZeroAddress

error ZeroAddress();

InviteValidationHook

Inherits: IValidationHook

CCA bid validation: require a valid invite code in hookData.

Constants

registry

InviteRegistry public immutable registry

Functions

constructor

constructor(InviteRegistry registry_) ;

validate

Validate a bid

MUST revert if the bid is invalid

function validate(uint256, uint128, address owner, address, bytes calldata hookData) external;

Parameters

NameTypeDescription
<none>uint256
<none>uint128
owneraddressThe owner of the bid
<none>address
hookDatabytesAdditional data to pass to the hook required for validation

Errors

InvalidHookData

error InvalidHookData();

LaunchFeeHook

Inherits: InitializerHook, IUnlockCallback

LBP-compatible InitializerHook that charges an afterSwap hook fee into FeeDistributor.

Constants

MAX_HOOK_FEE

uint24 internal constant MAX_HOOK_FEE = 1e6

distributor

FeeDistributor public immutable distributor

defaultHookFee

uint24 public immutable defaultHookFee

State Variables

hookFeeOf

mapping(PoolId => uint24) public hookFeeOf

feeConfigured

mapping(PoolId => bool) public feeConfigured

Functions

constructor

constructor(IPoolManager poolManager_, address authorized_, FeeDistributor distributor_, uint24 defaultHookFee_)
    InitializerHook(poolManager_, authorized_);

setPoolHookFee

function setPoolHookFee(PoolId poolId, uint24 fee) external;

getHookPermissions

function getHookPermissions() public pure override returns (Hooks.Permissions memory);

_afterSwap

function _afterSwap(
    address sender,
    PoolKey calldata key,
    SwapParams calldata params,
    BalanceDelta delta,
    bytes calldata
) internal override returns (bytes4, int128);

harvest

function harvest(PoolKey calldata key) external;

unlockCallback

function unlockCallback(bytes calldata data) external onlyPoolManager returns (bytes memory);

receive

receive() external payable;

Events

PoolHookFeeSet

event PoolHookFeeSet(PoolId indexed poolId, uint24 fee);

HookFee

event HookFee(bytes32 indexed poolId, address indexed sender, uint128 feeAmount0, uint128 feeAmount1);

Errors

InvalidFee

error InvalidFee();

HookFeeTooLarge

error HookFeeTooLarge();

FeeDistributor

Accrues hook fees and pays creator / referrers / platform via claim.

Split: 20% creator, 75% referrers (pro-rata by referral count), 5% platform.

Constants

PLATFORM

address public constant PLATFORM = 0xBb6f397d9d8bf128dDa607005397F539B43CD710

CREATOR_BPS

uint16 public constant CREATOR_BPS = 2_000

REFERRERS_BPS

uint16 public constant REFERRERS_BPS = 7_500

PLATFORM_BPS

uint16 public constant PLATFORM_BPS = 500

BPS_DENOM

uint16 public constant BPS_DENOM = 10_000

State Variables

referrals

IReferralSource public referrals

hook

address public hook

registrar

address public registrar

pools

mapping(PoolId => PoolInfo) public pools

creatorOwed

mapping(PoolId => mapping(address => uint256)) public creatorOwed

platformOwed

mapping(PoolId => mapping(address => uint256)) public platformOwed

referrerPool

mapping(PoolId => mapping(address => uint256)) public referrerPool

referrerClaimed

mapping(PoolId => mapping(address => mapping(address => uint256))) public referrerClaimed

Functions

onlyHook

modifier onlyHook() ;

receive

receive() external payable;

setReferrals

function setReferrals(address referrals_) external;

setHook

function setHook(address hook_) external;

setRegistrar

function setRegistrar(address registrar_) external;

registerPool

function registerPool(PoolId poolId, address auction, address creator) external;

notifyFee

function notifyFee(PoolId poolId, address currency, uint256 amount) external payable onlyHook;

claimCreator

function claimCreator(PoolId poolId, address currency) external returns (uint256 amount);

claimPlatform

function claimPlatform(PoolId poolId, address currency) external returns (uint256 amount);

claimReferrer

function claimReferrer(PoolId poolId, address currency) external returns (uint256 amount);

pendingReferrer

function pendingReferrer(PoolId poolId, address currency, address referrer) external view returns (uint256);

_pay

function _pay(address currency, address to, uint256 amount) internal;

Events

ReferralsSet

event ReferralsSet(address indexed referrals);

HookSet

event HookSet(address indexed hook);

RegistrarSet

event RegistrarSet(address indexed registrar);

PoolRegistered

event PoolRegistered(PoolId indexed poolId, address indexed auction, address indexed creator);

FeeNotified

event FeeNotified(PoolId indexed poolId, address indexed currency, uint256 amount);

Claimed

event Claimed(PoolId indexed poolId, address indexed currency, address indexed to, uint256 amount);

Errors

NotAuthorized

error NotAuthorized();

NotHook

error NotHook();

NotRegistered

error NotRegistered();

NothingToClaim

error NothingToClaim();

InvalidAmount

error InvalidAmount();

TransferFailed

error TransferFailed();

AlreadySet

error AlreadySet();

Structs

PoolInfo

struct PoolInfo {
    address creator;
    address auction;
    bool registered;
}

IReferralSource

Read referral weights for FeeDistributor claims.

Functions

referralCount

function referralCount(address auction, address referrer) external view returns (uint256);

totalReferralCount

function totalReferralCount(address auction) external view returns (uint256);