Klik Finance<- Back to app
Developer Docs
Overview
What is KlikFee ScheduleFactory Contracts
Launch
Launch SequenceFull Examples
APIs
Atomic EndpointUpload ImageUpload MetadataGenerate SaltRate Limits
Klik Finance

Developer Documentation

Last Updated: April 24, 2026

What is Klik?

Klik is a permissionless token launchpad on Ethereum mainnet and Base. Anyone can deploy a fully on-chain ERC-20 token with bootstrapped Uniswap V4 liquidity in a single transaction - no seed rounds, no VCs, no presales.

Every token launched through Klik:

  • Gets a vanity address starting with 69 (Ethereum) or 420 (Base), mined via CREATE2
  • Launches with real Uniswap V4 liquidity locked in the pool
  • Is immediately tradable with swap fees flowing to the creator and the platform

Note: In some cases, a token address might not start with 0x69 (or 0x420 on Base), and that is not an issue.

Fee Schedule

Klik charges a dynamic swap fee that decreases as the token's market cap grows. This rewards early believers and reduces friction for larger tokens. Fees are split between the platform and the token creator.

Market Cap (ETH)Total FeePlatformCreator
0 - 15 ETH1.25%0.80%0.45%
15 - 55 ETH1.20%0.70%0.50%
55 - 90 ETH1.15%0.60%0.55%
90 - 125 ETH1.10%0.55%0.55%
125 - 165 ETH1.05%0.52%0.53%
165 - 365 ETH1.00%0.50%0.50%
365 - 545 ETH0.95%0.47%0.48%
545 - 725 ETH0.90%0.44%0.46%
725 - 910 ETH0.85%0.41%0.44%
910 - 1090 ETH0.80%0.38%0.42%
1090 - 1275 ETH0.75%0.35%0.40%
1275 - 1450 ETH0.70%0.33%0.37%
1450 - 1635 ETH0.65%0.30%0.35%
1635 - 1815 ETH0.60%0.28%0.32%
1815 - 2000 ETH0.55%0.27%0.28%
2000 - 2175 ETH0.525%0.25%0.275%
>= 2175 ETH0.35%0.15%0.20%

Factory Contracts

Pass the correct factory address for your target chain when calling deployCoin or generating a salt.

ChainChain IDFactory Address
Ethereum10xDE60796060c24638c389eFBD36b6b919805CA655
Base84530xB6CB1c049ee8942683Fd3172f7EBA63B6e8a6835

Launch Sequence

Before the wallet signs, the current frontend does three backend calls in this order: upload image, upload metadata JSON, then generate the vanity salt.

Step 1 - Upload image

If the user attached an image, the frontend first calls /api/uploadImage with multipart form data and receives an image CID.

Step 2 - Upload metadata JSON

The frontend then calls /api/uploadMetadata. If an image exists, the metadata payload uses ipfs://<imageCid>. Otherwise it sends an empty string.

Step 3 - Generate salt

The frontend calls /api/generate-salt with the wallet address, chosen chain, and matching factory address.

Step 4 - Call deployCoin

function deployCoin(
  string calldata name,
  string calldata symbol,
  string calldata metadataUri,
  bytes32 salt,
  uint256 configId
) external payable;
  • metadataUri - the current frontend passes the raw metadata CID returned by /api/uploadMetadata
  • salt - the 0x-prefixed bytes32 value from /api/generate-salt
  • configId - Ethereum uses 0 to 4; Base uses 0
  • msg.value - optional creator buy amount

Ethereum liquidity tiers:

configIdStarting Liquidity
00.69 ETH
11 ETH
22 ETH
35 ETH
410 ETH

Base: only configId = 0 is available.

Creator Buy Penalty

⚠️ This will be deprecated soon — the penalty fee will not exist anymore.

If you pass a non-zero msg.value to deployCoin, the contract applies a penalty to discourage disproportionate supply accumulation by the creator at launch. The penalty is not a flat percentage — each liquidity config carries its ownpenaltyMultiplier, so the same creator buy amount results in a different penalty depending on which configId you picked.

The effective penalty is derived on-chain from two values:

  • getPenalty(ethAmount) — the base penalty for your buy size (in bps)
  • getLiquidityConfig(configId).penaltyMultiplier — a per-config scaling factor

Final penalty ≈ getPenalty(msg.value) × penaltyMultiplier. Higher-liquidity tiers tend to carry a lower multiplier, so a creator buy on a deeper pool is penalized less than the same buy on a shallower pool. Always simulate deployCoin with your intended msg.value before sending the transaction — the simulation returns the exact token amount you would receive, inclusive of penalty, so you can confirm the outcome instead of deploying blind.

Atomic Endpoint

Base URL: https://klik.finance

/api/uploadTokenMetadata is the one-call developer flow. It is not the path used by the in-app launch modal, but it is useful for external integrations.

Content-Type: multipart/form-data or application/json

Use multipart when sending an image. JSON mode is text-only.

FieldTypeRequiredDescription
namestringYesToken name
symbolstringYesToken ticker symbol
descriptionstringNoToken description
websitestringNoProject website URL
twitterstringNoTwitter/X handle or URL
telegramstringNoTelegram link
imagefileNoToken image, multipart only, max 1 MB
creatorstringNoWallet address, required if you want salt generation
factorystringNoFactory address, defaults to Ethereum
chainIdstringNo"1" or "8453"
testnetbooleanNoUse testnet RPC for salt generation
Example payload (multipart with image)
{
  "name": "My Token",
  "symbol": "MYT",
  "description": "Your token description",
  "creator": "0xYourWalletAddress",
  "chainId": "1",
  "image": "<binary file>"
}
Example payload (JSON without image)
{
  "name": "My Token",
  "symbol": "MYT",
  "description": "Your token description",
  "creator": "0xYourWalletAddress",
  "chainId": "1"
}

Response:

{
  "cid": "QmXyz...",
  "url": "QmXyz...",
  "imageCid": "QmAbc...",
  "salt": "0xdeadbeef...",
  "saltAddress": "0x69ab12...",
  "targetPrefix": "69",
  "hasTargetPrefix": true
}

Upload Image

Endpoint: POST /api/uploadImage

Content-Type: multipart/form-data

FieldTypeRequiredDescription
filefileYesImage file, max 1 MB
Frontend payload
{
  "file": "<binary file>"
}

Response:

{ "cid": "QmAbc...", "url": "QmAbc..." }

Upload Metadata

Endpoint: POST /api/uploadMetadata

Content-Type: application/json

The frontend sends this payload before launch.

Frontend payload
{
  "name": "My Token",
  "symbol": "MYT",
  "description": "Your token description",
  "image": "ipfs://QmImageCid...",
  "website": "https://mytoken.com",
  "twitter": "https://x.com/mytoken",
  "telegram": "https://t.me/mytoken"
}

Example payload:

{
  "name": "My Token",
  "symbol": "MYT",
  "description": "Your token description",
  "image": "ipfs://QmAbc...",
  "website": "https://mytoken.com",
  "twitter": "https://x.com/mytoken",
  "telegram": "https://t.me/mytoken"
}

Response:

{ "cid": "QmXyz...", "url": "QmXyz..." }

Generate Salt

Endpoint: POST /api/generate-salt

The frontend sends the chain-specific factory address along with the wallet address.

FieldTypeRequiredDescription
namestringYesToken name
symbolstringYesToken symbol
creatorstringYesCreator wallet address
factorystringNoFactory address, defaults to Ethereum factory
chainIdstringNo"1" or "8453"
testnetbooleanNoUse testnet RPC
num_matchesnumberNoDefaults to 1
max_attemptsnumberNoDefaults to 25000
Frontend payload
{
  "name": "My Token",
  "symbol": "MYT",
  "creator": "0xYourWalletAddress",
  "factory": "0xDE60796060c24638c389eFBD36b6b919805CA655",
  "chainId": "1"
}

Response:

{
  "factory": "0xDE60796060c24638c389eFBD36b6b919805CA655",
  "target_prefix": "69",
  "total_attempts": 4821,
  "has_target_prefix": true,
  "results": [
    { "salt": "0xdeadbeef...", "address": "0x69ab12..." }
  ]
}

If has_target_prefix is false, the endpoint still returns a valid fallback salt.

Rate Limits

All endpoints enforce per-IP rate limits.

EndpointPer SecondPer Minute
/api/uploadImage30120
/api/uploadMetadata30120
/api/uploadTokenMetadata1060
/api/generate-salt-60
/api/search6100
/api/sort-mcap640
/api/sort-trending430
/api/deployed-tokens420
/api/ecosystem-stats420
{
  "error": "Rate limit exceeded",
  "message": "Too many requests per second. Please slow down.",
  "resetIn": 1,
  "type": "second"
}

Full Examples

These examples match the current app flow more closely than the previous version: metadata upload, salt generation, then deployCoin.

JavaScript (ethers)

Install: npm install ethers

import { ethers } from 'ethers';

const FACTORY_ABI = [
  'function deployCoin(string name, string symbol, string metadataUri, bytes32 salt, uint256 configId) payable'
];

const RPC_URL = 'https://rpc.mevblocker.io/fast';
const PRIVATE_KEY = '0xyour_private_key_here';
const CHAIN_ID = '1';
const FACTORY_ADDRESS = '0xDE60796060c24638c389eFBD36b6b919805CA655';

const TOKEN_NAME = 'My Token';
const TOKEN_SYMBOL = 'MYT';
const TOKEN_DESCRIPTION = 'Your token description';
const CONFIG_ID = 1n;
const CREATOR_BUY_ETH = '0';

async function main() {
  const provider = new ethers.JsonRpcProvider(RPC_URL);
  const wallet = new ethers.Wallet(PRIVATE_KEY, provider);
  const creator = await wallet.getAddress();

  const metadataRes = await fetch('https://klik.finance/api/uploadMetadata', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      name: TOKEN_NAME,
      symbol: TOKEN_SYMBOL,
      description: TOKEN_DESCRIPTION,
      image: '',
      website: '',
      twitter: '',
      telegram: '',
    }),
  });
  if (!metadataRes.ok) throw new Error(await metadataRes.text());
  const { cid } = await metadataRes.json();

  const saltRes = await fetch('https://klik.finance/api/generate-salt', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      name: TOKEN_NAME,
      symbol: TOKEN_SYMBOL,
      creator,
      factory: FACTORY_ADDRESS,
      chainId: CHAIN_ID,
    }),
  });
  if (!saltRes.ok) throw new Error(await saltRes.text());
  const saltPayload = await saltRes.json();
  const salt = saltPayload.results[0].salt;

  const factory = new ethers.Contract(FACTORY_ADDRESS, FACTORY_ABI, wallet);
  const tx = await factory.deployCoin(
    TOKEN_NAME,
    TOKEN_SYMBOL,
    cid,
    salt,
    CONFIG_ID,
    { value: ethers.parseEther(CREATOR_BUY_ETH) }
  );

  console.log('Broadcasted tx:', tx.hash);
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});

Python (web3.py)

Install: pip install web3 requests

import requests
from web3 import Web3

FACTORY_ABI = [
    {
        "type": "function",
        "name": "deployCoin",
        "stateMutability": "payable",
        "inputs": [
            {"name": "name", "type": "string"},
            {"name": "symbol", "type": "string"},
            {"name": "metadataUri", "type": "string"},
            {"name": "salt", "type": "bytes32"},
            {"name": "configId", "type": "uint256"}
        ],
        "outputs": []
    }
]

RPC_URL = "https://rpc.mevblocker.io/fast"
PRIVATE_KEY = "0xyour_private_key_here"
CHAIN_ID = "1"
FACTORY_ADDRESS = "0xDE60796060c24638c389eFBD36b6b919805CA655"

TOKEN_NAME = "My Token"
TOKEN_SYMBOL = "MYT"
TOKEN_DESCRIPTION = "Your token description"
CONFIG_ID = 1
CREATOR_BUY_ETH = "0"

w3 = Web3(Web3.HTTPProvider(RPC_URL))
account = w3.eth.account.from_key(PRIVATE_KEY)
creator = account.address

metadata_res = requests.post(
    "https://klik.finance/api/uploadMetadata",
    json={
        "name": TOKEN_NAME,
        "symbol": TOKEN_SYMBOL,
        "description": TOKEN_DESCRIPTION,
        "image": "",
        "website": "",
        "twitter": "",
        "telegram": "",
    },
    timeout=60,
)
metadata_res.raise_for_status()
cid = metadata_res.json()["cid"]

salt_res = requests.post(
    "https://klik.finance/api/generate-salt",
    json={
        "name": TOKEN_NAME,
        "symbol": TOKEN_SYMBOL,
        "creator": creator,
        "factory": FACTORY_ADDRESS,
        "chainId": CHAIN_ID,
    },
    timeout=60,
)
salt_res.raise_for_status()
salt = salt_res.json()["results"][0]["salt"]

factory = w3.eth.contract(
    address=Web3.to_checksum_address(FACTORY_ADDRESS),
    abi=FACTORY_ABI,
)

deploy_call = factory.functions.deployCoin(
    TOKEN_NAME,
    TOKEN_SYMBOL,
    cid,
    bytes.fromhex(salt[2:]),
    CONFIG_ID,
)

value_wei = w3.to_wei(CREATOR_BUY_ETH, "ether")
tx = deploy_call.build_transaction(
    {
        "from": creator,
        "chainId": int(CHAIN_ID),
        "nonce": w3.eth.get_transaction_count(creator),
        "value": value_wei,
    }
)
tx["gas"] = deploy_call.estimate_gas({"from": creator, "value": value_wei})

latest_block = w3.eth.get_block("latest")
if latest_block.get("baseFeePerGas") is not None:
    tx["maxPriorityFeePerGas"] = w3.to_wei(1, "gwei")
    tx["maxFeePerGas"] = latest_block["baseFeePerGas"] * 2 + tx["maxPriorityFeePerGas"]
else:
    tx["gasPrice"] = w3.eth.gas_price

signed_tx = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
print("Broadcasted tx:", tx_hash.hex())

receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print("Confirmed in block:", receipt.blockNumber)