Protocol Architecture
LP24 consists of six smart contracts that work together to manage the full token lifecycle. All contracts are written in Vyper 0.4.3 and deployed as minimal proxies (EIP-1167) where applicable.
Contract Overview
| Contract | Pattern | Role |
|---|---|---|
Factory_v2 | Singleton | Entry point. Deploys token + bonding curve pairs via CREATE2 with vanity address enforcement. |
TokenTemplate | Minimal Proxy | ERC-20 token with minter-only mint/burn, trading lock until graduation, and 9-decimal precision. |
BondingCurveTemplate | Minimal Proxy | Manages bonding curve trading, price calculation, graduation trigger, and refund system. |
LiquidityGenHook | Singleton (Uniswap V4 Hook) | All-in-one post-graduation manager: fee collection, LP management, fee distribution, reinvestment, CTO voting. |
CTOVoteTemplate | Minimal Proxy | Community Takeover voting logic. Cloned per-vote by the Hook. |
TokenSocials | Singleton | On-chain registry for token metadata (socials). Packed bytes32 storage. |
Interaction Flow
The contracts interact in a specific sequence during the token lifecycle:
Deployment
User → Factory.deploy_pair(name, symbol, salt, packed_socials)
├─→ create_minimal_proxy_to(token_master, salt) → TokenTemplate clone
├─→ create_minimal_proxy_to(bonding_curve_master) → BondingCurve clone
├─→ TokenTemplate.initialize(name, symbol, curve)
├─→ BondingCurve.initialize(token) {value: deployment_fee}
└─→ TokenSocials.register_token(token, deployer, packed_socials)
Buy on Bonding Curve
User → BondingCurve.buy(token_lots) {value: total_price}
├─→ TokenTemplate.balanceOf(user) // check user limit
├─→ _calculate_price(supply, lots, true) // quadratic pricing
├─→ TokenTemplate.mint(user, lots * LOT_SIZE)
└─→ if supply == MAX_SUPPLY_LOTS:
└─→ _graduate()
├─→ raw_call(deployer, fees * 90%)
├─→ TokenTemplate.mint(HOOK, 400M tokens)
├─→ TokenTemplate.enableTrading()
└─→ Hook.createPositionAndRegister(token, deployer)
Graduation (inside Hook)
BondingCurve → Hook.createPositionAndRegister(token, deployer) {value: ETH}
├─→ IERC20(token).approve(PERMIT2, MAX)
├─→ IAllowanceTransfer.approve(token, POSITION_MANAGER, MAX)
├─→ PositionManager.multicall([initializePool, modifyLiquidities])
├─→ platformBalance += excess ETH
└─→ tokenInfo[token] = {deployer, positionId}
Post-Graduation Swap (via Uniswap V4)
User → UniversalRouter.execute(swap)
└─→ PoolManager calls Hook:
├─→ beforeSwap() // Tax buys: take ETH fee from PoolManager
└─→ afterSwap() // Tax sells: take ETH fee from PoolManager
// Fees accumulate in pendingFees[token]
Design Principles
No Admin Keys
The protocol is fully permissionless. There is no owner, no admin, no multisig, and no upgrade path. Once deployed, the contracts are immutable. The only privileged role is "deployer" which receives fee shares — and even that can be transferred via CTO vote.
Gas Optimization
The contracts are heavily gas-optimized. Key techniques include:
- No per-user storage on the bonding curve (saves ~17k gas on first buy per user)
- Token balance checked via
balanceOf()instead of internal mapping - Transient storage (EIP-1153) for the internal swap flag on the Hook
- Standalone
pendingFeesmapping instead of struct field (saves ~200 gas/swap) - Cached fee tiers with lazy computation
Minimal Proxy Pattern
Tokens, bonding curves, and CTO vote contracts are deployed as EIP-1167 minimal proxies. This means each new deployment is a tiny bytecode stub that delegates all calls to a shared implementation contract. Deployment cost is ~45k gas instead of ~2M gas for a full contract.