Architecture
How the Launcher, Fee Hook, Router, Quoter, Rulebook, pair list and token fit together, and how a token graduates.
The contracts
| Contract | Job | State it keeps |
|---|---|---|
| CastToken | One per launch. An ERC-20 that stores its sealed rules, its paired asset, Hold Streaks, max wallet and holder rewards. | Rules, balances, streaks, rewards |
| CastLauncher | Creates tokens, opens their bonding curves and creates their pools. | List of every CAST token |
| CastHook | The Uniswap v4 hook. Runs each token's bonding curve, charges fees in the paired asset on every trade, and graduates the token into its pool. Refuses every other liquidity change. | Each token's curve, fees owed to creators and CAST, counters |
| CastRouter | Buys and sells, and names the trader to the hook. Only trades tokens whose pool uses the CAST hook. | None (the PoolManager and hook addresses are fixed at deploy) |
| CastQuoter | Read-only fee quotes. | None |
| CastRulebook | Safety limits and the grading formula. | None |
| CastPairs | The approved list of assets a token can be paired with, and the bonding curve for each. Only affects new launches. | Listed assets, open or closed, with each one's virtual reserve and graduation target |
| FeeRecipient | Where CAST's 20% goes. Its controller also manages CastPairs. | One payout address and its controller |
What happens at launch
All of this happens in one transaction. If any step fails, nothing is created.
- 1Check the pairCastPairs.curveFor
The paired asset must be open on the pair list. Its virtual reserve and graduation target set the token's curve.
- 2ValidateRulebook.validate
The rules are checked against every safety limit and graded.
- 3Deploy the tokenCREATE2
The address is derived from the creator and a salt, so nobody else can take it. It must sort above the paired asset's address.
- 4Open the curveCastHook.openCurve
The hook records the token's curve and works out its final price, where it will graduate. Emits CurveOpened.
- 5Create the poolPoolManager.initialize
A pool of the paired asset (currency0) and the token (currency1) with the CAST hook, priced at the curve's final price. It holds no liquidity until graduation.
- 6Hand over the tokens
Every token for sale, which is the whole supply less any creator allocation, goes to the hook, held as PoolManager claims. The curve sells from them, and the rest wait for graduation.
- 7Creator's first buy
Optional. A normal buy on the curve, paid in the paired asset, that pays the launch-block fees. A big enough first buy graduates the token straight away.
- 8AnnounceLaunched
An event with the token, creator, paired asset, grade, score and a hash of the rules.
Graduation
Every token starts on a bonding curve that the hook runs inside the token's own pool. It is constant product on virtual reserves, in the same shape as pump.fun's: the paired-asset side is virtualPair + raised and the token side is virtualToken - sold, and the virtual reserve is 30/85 of the graduation target. About 79.3% of the tokens for sale are sold on the curve.
When a buy takes raised to the target, the token graduates inside that same buy:
- 1The last curve buyCurveTrade
The hook fills the buy up to the target, and the buyer gets the curve's last tokens.
- 2Add the positionGraduated
Everything the curve raised and the remaining tokens, about 20.7% of those for sale, go into one full-range Uniswap v4 position at exactly the curve's final price, so the price carries on where the curve left off.
- 3Finish the buySwap
Whatever is left of that buy swaps in the new pool, paying the sealed fees as usual.
- 4From then on
Every trade runs in the pool. The position is locked forever: the hook refuses every removal, and refuses every add by anyone, so it is the only liquidity the pool ever has.
What happens in a trade
- 1Wallet
Calls the CAST Router with an amount of the paired asset, a minimum amount out and a deadline. ETH is sent as value; an ERC-20 is taken from the wallet with an approval or a permit.
- 2RouterPoolManager.unlock
Checks that the token's pool uses the CAST hook (NotCastToken otherwise), then opens an exact-input swap on it and names the trader in the hook data.
- 3Fee HookbeforeSwap / afterSwap
While the token's max wallet applies, refuses a buy from any router but the CAST Router and Launcher (BuyNeedsCastRouter). Reads the token's rates for this moment and trader, takes the fee, and records who is owed what.
- 4Curve or pool
Before graduation the hook fills the whole trade from the curve and the pool swaps nothing. After graduation the swap runs against the locked liquidity. Either way, the token checks max wallet and updates Hold Streak.
- 5PayoutCastHook.distribute
The router asks the hook to send holders their share in the paired asset and burn the burn share. The burn always happens. If the reward payout fails, the rewards stay pending for the next distribute, and the trade still goes through.
| On the curve | In the pool | |
|---|---|---|
| Who fills it | The hook, from the curve | The locked pool position |
| Price | (virtualPair + raised) / (virtualToken - sold) | The pool's sqrtPriceX96 |
| Sealed rules | Bot Tax, buy and sell fees, burn share, max wallet and Hold Streak, exactly as in the pool | The same |
| 0.3% pool fee | None, as there is no pool position yet | Charged on every trade and left in the pool |
| Exact output | Not accepted: CurveIsExactInputOnly | Accepted |
| What gets logged | CurveTrade and FeeCharged from the hook, and a Swap from the PoolManager with zero amounts | Swap from the PoolManager, FeeCharged from the hook |
Paying out
Three functions turn what the hook holds into real payments. Anyone can call them; the money only ever goes to its owner.
| Function | Pays | Called by |
|---|---|---|
| distribute(token) | Holder rewards into the token's stream, and burns the burn share. The burn never waits on the rewards | The Router after every trade |
| claimCreatorFees(token) | The creator's share, in the token's paired asset, to the token's creator | The creator, from their profile |
| withdrawCastFees(asset) | CAST's share in one paired asset, to the address set in the Fee Recipient | Anyone |
Every payout is made in the paired asset. If that asset pauses transfers or freezes a wallet, only payouts involving it fail, and what's owed stays recorded. The router calls distribute in a try/catch, so a failed payout never blocks a trade. Inside distribute, the burn always happens; if the reward payout fails (for example USDG froze the token or the hook), the hook logs HolderRewardsDeferred and keeps the rewards pending, and the next distribute after the problem clears delivers them.
Holders collect their own rewards from the token with claim(). See Holder rewards.