mint.fast docs

Deploy a coin

How createToken works, beneficiary rules, and a full viem example.

What happens in one transaction

createToken does all of this atomically:

  1. Checks creates are not paused and msg.value >= creationFee
  2. Validates metadata lengths
  3. CREATE2-deploys MintFastToken (1B supply minted to the launchpad)
  4. Snapshots the current default Fletcher / LP fee splits onto the token
  5. Registers beneficiaries (or defaults 100% to the creator wallet)
  6. Accrues the creation fee into protocolFeesAccrued
  7. Initializes the Uniswap v4 pool and locks the full supply
  8. If you sent ETH above the creation fee, runs an atomic first buy to msg.sender

Function signature

function createToken(
    string calldata name,
    string calldata symbol,
    string calldata metadataURI,
    BeneficiaryInput[] calldata beneficiaries,
    uint256 initialBuyMinTokensOut,
    bytes32 salt
) external payable returns (address token);

Parameters

ParamRules
name1 to 32 bytes
symbol1 to 10 bytes
metadataURIup to 256 bytes (usually an ipfs:// or https://ipfs.io/ipfs/... URL)
beneficiaries0 to 8 rows, bps sum to 10_000 if non-empty
initialBuyMinTokensOutslippage floor for the optional first buy (use 0 if no buy)
saltyour entropy mixed into CREATE2, so retries and grief resistance stay practical
msg.valueat least creationFee, plus any ETH you want to spend on the first buy

BeneficiaryInput

struct BeneficiaryInput {
    uint8 kind;      // 1 = X, 2 = GitHub, 3 = Wallet
    string handle;   // normalized handle for X/GitHub, empty for Wallet
    address wallet;  // payout address for Wallet, address(0) for social
    uint16 bps;      // share of the Fletcher cut, all rows sum to 10000
}

Handles must already be lowercase / canonical. See HandleLib.

Empty vs named beneficiaries

  • Empty array: creator gets 100% via a wallet key, list stays unlocked, creator may call setBeneficiaries once later.
  • Named list: locked in the same create tx. Typos need a CTO / fee-manager path.

Example: mint with an X Fletcher and a first buy

import {
  createWalletClient,
  createPublicClient,
  http,
  parseEther,
  encodeFunctionData,
  type Hex,
} from "viem"
import { privateKeyToAccount } from "viem/accounts"

const LAUNCHPAD = "0xYourLaunchpad" as const
const creationFee = parseEther("0.0005")
const firstBuy = parseEther("0.05")

const createTokenAbi = [
  {
    type: "function",
    name: "createToken",
    stateMutability: "payable",
    inputs: [
      { name: "name", type: "string" },
      { name: "symbol", type: "string" },
      { name: "metadataURI", type: "string" },
      {
        name: "beneficiaries",
        type: "tuple[]",
        components: [
          { name: "kind", type: "uint8" },
          { name: "handle", type: "string" },
          { name: "wallet", type: "address" },
          { name: "bps", type: "uint16" },
        ],
      },
      { name: "initialBuyMinTokensOut", type: "uint256" },
      { name: "salt", type: "bytes32" },
    ],
    outputs: [{ name: "token", type: "address" }],
  },
] as const

const account = privateKeyToAccount(process.env.PRIVATE_KEY as Hex)
const client = createWalletClient({
  account,
  transport: http(process.env.RPC_URL),
})
const publicClient = createPublicClient({ transport: http(process.env.RPC_URL) })

const salt = ("0x" +
  Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString("hex")) as Hex

const hash = await client.writeContract({
  address: LAUNCHPAD,
  abi: createTokenAbi,
  functionName: "createToken",
  args: [
    "Cool Coin",
    "COOL",
    "ipfs://bafybeigexamplemetadata",
    [
      {
        kind: 1, // X
        handle: "alice",
        wallet: "0x0000000000000000000000000000000000000000",
        bps: 10000,
      },
    ],
    0n, // tighten with a quoter-style estimate in production
    salt,
  ],
  value: creationFee + firstBuy,
})

const receipt = await publicClient.waitForTransactionReceipt({ hash })
console.log("mined", receipt.transactionHash)

Rough first-buy size estimate

Before the pool exists you cannot call quoteBuy. Near launch geometry, this constant-product style estimate tracks well (2% fee netted first, ~1.5 ETH virtual reserve, 1B supply):

const TOTAL_SUPPLY = 1_000_000_000n * 10n ** 18n
const LAUNCH_MCAP_WEI = 1_500_000_000_000_000_000n // 1.5 ETH
const FEE_BPS = 200n

function estimateInitialBuyTokens(ethIn: bigint): bigint {
  if (ethIn <= 0n) return 0n
  const ethNet = ethIn - (ethIn * FEE_BPS) / 10_000n
  if (ethNet <= 0n) return 0n
  return (TOTAL_SUPPLY * ethNet) / (LAUNCH_MCAP_WEI + ethNet)
}

Use that (minus a slippage buffer) as initialBuyMinTokensOut when you send a first buy.

Common reverts

ErrorUsual cause
CreationPausedowner paused new creates
InsufficientCreationFeemsg.value below creationFee
BadMetadataname / symbol / URI length
InvalidHandlehandle not canonical for the platform
BpsSumMismatchbeneficiary bps do not sum to 10_000
TooManyBeneficiariesmore than 8
Slippagefirst buy got fewer tokens than initialBuyMinTokensOut

After create