Skip to content

Launch a token with a revenue token

From the launch floor or a script: predictRevenueToken, every royalty pointed at it, then launchAndTokenize in one transaction.

On this page

A new Hookr launch can mint a revenue token in the same transaction: the tokenizer launches the family through the launcher, locks it, and mints a token whose income is the pools' LP fees, arb recapture, royalty and the Hook Block takes that name it.

In the app

  1. Set up the launch on the launch floor as usual: the token, its pools and their Hook Blocks.
  2. On the Revenue step, under Creator income, switch on Hookr Multi-stream Revenue Tokenizer. The row lists the pools that will pay the revenue token, then its terms: name, ticker and supply, the term, the release period of 1 to 14 days, who receives the minted tokens, and the market at mint.
  3. The Review step spells out every choice the revenue token fixes. Sign: the ERC-20 budgets are approved to the tokenizer, then one transaction to the tokenizer launches, locks and mints.

For a new Hookr pool of a token that already trades, open the New pool tab on /tokenize: it opens the launch floor on that token with the revenue token switched on.

The calls

  1. Build the launch's LaunchParams exactly as for the launcher's launchFamily: the launcher guide and hookr-sdk's buildLaunchFamily cover every field, and buildLaunchFamily gives the value that call would carry.
  2. predictRevenueToken(creator, p, t) gives the revenue token's address before it exists. It is worked out from the creator and the token's name, symbol, supply, assets (ETH, the pools' quotes, the launched token and extraAssets), release period, tip and termsHash; the recipients, the amounts and the royalty recipients do not move it.
  3. Point every pool's royalty at it: royaltyTo is the token where royaltyBps is above zero and zero where it is not. A pool binding Tax + Conversion names the token, or zero, as both creator recipients of both legs of its bind data. Any other Hook Block with a Hook Block take in the quote pays it to its own recipient, and the tokenizer reports it with AdvisoryPayeeUnchecked.
  4. launchAndTokenize(p, t, l, m), with the launch's value plus the launcher's launchFee() once more when the market opens. ERC-20 budgets are pulled from the creator, approved to the tokenizer rather than the launcher. l.unlockBlock is the family's term: a parent-chain block at least 50,400 past the current one, or the largest uint64 for good.
  5. The call gives back the token, the family door, the family, the market's family, the launched token and what its dev buys delivered, so an eth_call of it quotes a dev buy. The receipt's Tokenized records way 1, or way 3 for a new pool of a token that trades.

At the end of a term the family goes back to the creator, and each pool's royalty keeps paying the token: Terms and endings.

In code

With client.ts and abis.ts:

import { keccak256, parseEventLogs, parseUnits, toHex, zeroAddress, type Account, type ContractFunctionArgs, type WalletClient } from "viem";
import { client, parentBlock, TOKENIZER } from "./client";
import { launchFeeAbi, tokenizerAbi } from "./abis";

type LaunchParams = ContractFunctionArgs<typeof tokenizerAbi, "payable", "launchAndTokenize">[0];

// `p` is the LaunchParams you would send to the launcher's launchFamily, and `launchValue` that call's value:
// build both with hookr-sdk's buildLaunchFamily, as the launcher guide shows.
export async function launchWithRevenueToken(wallet: WalletClient, creator: Account, p: LaunchParams, launchValue: bigint) {
  const supply = parseUnits("100000000", 18);
  const seed = parseUnits("1000000", 18);
  const terms = {
    name: "Example Launch Revenue",
    symbol: "rLAUNCH",
    supply,
    streamSeconds: 86_400,
    tipBps: 100,
    extraAssets: [],
    recipients: [creator.address],
    amounts: [supply - seed], // a launch is on the Hookr hook: no leg
    termsHash: keccak256(toHex("rLAUNCH: 100,000,000 supply, locked 28 days")),
  };

  // 1. The revenue token's address, before anything exists, and every royalty pointed at it.
  const revenueToken = await client.readContract({ address: TOKENIZER, abi: tokenizerAbi, functionName: "predictRevenueToken", args: [creator.address, p, terms] });
  const params = {
    ...p,
    members: p.members.map((m) => ({ ...m, rules: { ...m.rules, royaltyTo: m.rules.royaltyBps > 0 ? revenueToken : zeroAddress } })),
  };

  // 2. The term, in parent-chain blocks: 28 days. MIN_TERM_BLOCKS is 50,400, seven days.
  const unlockBlock = (await parentBlock()) + 4n * 50_400n;

  // 3. The market at mint on the tokenizer's own terms, and the launch fee once more for it.
  const sqrt = (n: bigint) => {
    let x = n;
    let y = (x + 1n) / 2n;
    while (y < x) [x, y] = [y, (y + n / y) / 2n];
    return x;
  };
  const market = await client.readContract({ address: TOKENIZER, abi: tokenizerAbi, functionName: "defaultMarket", args: [sqrt(10_000_000n << 192n), seed] });
  const launcher = await client.readContract({ address: TOKENIZER, abi: tokenizerAbi, functionName: "launcher" });
  const [launchFee] = await client.readContract({ address: launcher, abi: launchFeeAbi, functionName: "launchFee" });

  // 4. One call launches, locks and mints. ERC-20 budgets are approved to the tokenizer, not the launcher.
  const { request } = await client.simulateContract({
    account: creator,
    address: TOKENIZER,
    abi: tokenizerAbi,
    functionName: "launchAndTokenize",
    args: [params, terms, { unlockBlock }, market],
    value: launchValue + launchFee,
  });
  const receipt = await client.waitForTransactionReceipt({ hash: await wallet.writeContract(request) });
  return parseEventLogs({ abi: tokenizerAbi, eventName: "Tokenized", logs: receipt.logs })[0].args;
}

The app opens the market on the launch's first pool's settings, with its quote set to ETH and no Hook Block; defaultMarket gives the tokenizer's own. Either way the tokenizer points the market's royalty at the token itself.

Fee

A launch's pools are on the Hookr hook and pay Hookr through it, so the mint gives Hookr no leg of the supply: the recipients' amounts are the supply less the market's seed.