Reference
Launchpad SDK
@cc0company/sdk — launch tokens, claim creator fees, stake $cc0company and ship NFT drops from any website, app or agent. One dependency: viem.
Install
npm install @cc0company/sdk viem
Current version: 1.12.0. Open source on GitHub (CC0-1.0, of course). Five clients:
Cc0Launchpad— ERC-20 launches.Cc0B20Launchpad— B20 launches (Base only).Cc0Fees— read and claim creator fees.Cc0Staking— stake $cc0company, earn WETH.Cc0Drops— IPFS NFT drops (ERC-721 + ERC-1155): pin art, pin metadata, deploy, configure phases.
Upgrade off 1.11.x
creatorRewards[0]. On a Community Coin launch that slice is the distributor contract, so the vault was locked forever. In 1.12.0 creatorRewards slices are fees only — non-fee proceeds go to the launching account or to an explicit proceedsRecipient.Chains
Every client takes a chain — the slug 'base', 'ethereum', 'robinhood', or the id 8453, 1, 4663. Defaults to Base.
| Capability | Base | Ethereum | Robinhood |
|---|---|---|---|
| Standard ERC-20 launch (75/15/10) | Yes | Yes | Yes |
| Paired ERC-20 launch (80/20) | Yes | No | Yes |
| Community Coin (fees to NFT holders) | Yes | Yes | Yes |
| B20 launch | Yes | No | No |
| $cc0company staking pool | Yes | Forwarder only | Escrow only |
Check paired availability at runtime rather than hardcoding it — isCc0PairedAvailable(chain) is derived from the address book and fails closed.
Ethereum RPC
eth.merkle.io) is CORS-blocked in browsers. The SDK ships a working default per chain (DEFAULT_RPCS); pass your own rpcUrl in production.Launch a token
import { Cc0Launchpad } from '@cc0company/sdk';
import { createWalletClient, custom } from 'viem';
import { base } from 'viem/chains';
const walletClient = createWalletClient({
chain: base,
transport: custom(window.ethereum),
});
// chain: 'base' | 'ethereum' | 'robinhood' (or 8453 | 1 | 4663)
const launchpad = new Cc0Launchpad({ walletClient, chain: 'base' });
const { tokenAddress, txHash, registered } = await launchpad.launchToken({
name: 'My Token',
symbol: 'MTK',
image: imageBytes, // any https URL, data: URL, Blob or bytes — pinned to
// IPFS by cc0.company automatically (the URI is written
// onchain forever). ipfs:// URIs pass through untouched.
description: 'My awesome token', // stored onchain
feeTier: 1, // 1 | 2 | 3 | 6.9 — or feeMode: 'dynamic'
});One transaction: token + Uniswap V4 pool + locked LP + fee split, atomically. The deployer's wallet signs; the token is live and tradable the moment the transaction lands.
Any wallet — browser, private key, CDP, Bankr, Safe
Every client takes a viem walletClient, a viem account (e.g. privateKeyToAccount), or a provider-agnostic sender — { address, send }. With a sender, the SDK builds the transaction (image pinned, gas + EIP-1559 fees pre-estimated, BigInt-free tx.json for JSON transports), your infra signs and submits, the SDK waits, parses and registers. Coinbase CDP, Bankr and Safes all integrate this way — full recipes in the README.
All options
await launchpad.launchToken({
name: 'My Token',
symbol: 'MTK',
image: imageBytes, // pinned to IPFS automatically
imagePolicy: 'pin', // 'pin' (default) | 'as-is'
// Fees — static tier or dynamic volatility preset
feeMode: 'static', // 'static' (default) | 'dynamic'
feeTier: 1, // 1 | 2 | 3 | 6.9 (static only)
// Split YOUR 75% across up to 5 wallets — FEES ONLY.
// (bps of total fees — must sum to exactly 7500)
creatorRewards: [
{ recipient: '0xYou', bps: 5000, feePreference: 'both' },
{ recipient: '0xCofounder', bps: 2500, feePreference: 'paired' },
],
// Vault admin, airdrop admin and dev-buy tokens. NEVER derived from
// creatorRewards. Defaults to the launching account.
proceedsRecipient: '0xYou',
// Metadata-only admin. DEFAULT address(0) — born renounced.
// tokenAdmin: '0xYou', // scanners will flag NOT renounced
// Anti-snipe: descending tax… or omit for the 2-block MEV delay
sniperTax: { startingBps: 800_000, endingBps: 50_000, secondsToDecay: 15 },
// Lock supply for yourself (lockup >= 7 days, optional vesting)
vault: { percentage: 10, lockupSeconds: 604800, vestingSeconds: 2592000 },
// Merkle airdrop (lockup >= 1 day); entriesCid = Pinata CID of the leaves
airdrop: { merkleRoot: '0x…', percentage: 5, entriesCid: 'bafy…' },
// Buy your own token at launch (not available on paired launches)
devBuyEth: '0.05',
// Liquidity profile — 'degen' (DEFAULT, thin) | 'classic' (deep)
lpPreset: 'degen',
});Paired launches
Pass pairedToken to quote the pool in an arbitrary ERC-20 instead of WETH. The split becomes 80% you / 20% treasury (no staker slice) and the launch routes through the separate dual-mode suite. Symbol and decimals are read on-chain; the WETH price resolves from the cc0.company price API unless you pass priceWeth — fail-closed, no price means no launch.
Not yet combinable with devBuyEth, creatorRewards or nftCollection. Available on Base and Robinhood Chain only.
import { isCc0PairedAvailable, PAIRED_SPLIT } from '@cc0company/sdk';
// PAIRED_SPLIT = { CREATOR_BPS: 8000, TREASURY_BPS: 2000 }
if (!isCc0PairedAvailable('robinhood')) throw new Error('no paired suite here');
const launchpad = new Cc0Launchpad({ walletClient, chain: 'robinhood' });
await launchpad.launchToken({
name: 'My Token',
symbol: 'MTK',
image: imageBytes,
pairedToken: { address: '0x…' }, // e.g. an official Robinhood stock token
});Community Coins — fees to NFT holders
nftCollection routes the whole creator slice to the holders of an ERC-721 collection. The SDK deploys a per-token Cc0NftFeeDistributor (an extra transaction through your signer), wires it as the sole creator recipient with fee preference both, and freezes it there. The collection must be on the same chain as the token — the distributor calls ownerOf locally.
await launchpad.launchToken({
name: 'Community Coin',
symbol: 'CC',
image: imageBytes,
nftCollection: {
address: '0x…', // ERC-721, sequential ids, same chain
maxEligibleTokenId: 9999n, // eligibility ceiling at launch
},
});
// On the manual prepareLaunchTransaction() path the SDK can't auto-deploy —
// deploy it yourself and pass the address as a creatorRewards recipient:
const distributor = await launchpad.deployNftDistributor('0x…', 9999n);The enforced split
Every launch carries the protocol split — validated by the factory onchain, not by this SDK:
- Standard (WETH pool) — 75% creator / 15% stakers / 10% treasury.
- Paired (any ERC-20 pool) — 80% creator / 20% treasury.
- A config that drops or resizes the protocol slices reverts with
Cc0InvalidProtocolSplit, even on a raw factory call.
import { PROTOCOL_SPLIT, PAIRED_SPLIT } from '@cc0company/sdk';
// PROTOCOL_SPLIT = { CREATOR_BPS: 7500, STAKING_BPS: 1500, TREASURY_BPS: 1000 }
// PAIRED_SPLIT = { CREATOR_BPS: 8000, TREASURY_BPS: 2000 }
// Live protocol addresses, read from the factory:
const { staking, treasury, admin } = await launchpad.getProtocolAddresses();Claim fees
Cc0Fees reads and claims on whichever chain you point it at. It resolves the pool's paired asset from the launch registry automatically, so a paired launch claims three assets, a standard one claims two. Claims are permissionless: the configured signer pays gas, the funds go to feeOwner.
import { Cc0Fees } from '@cc0company/sdk';
const fees = new Cc0Fees({ walletClient, chain: 'ethereum' });
const claimable = await fees.getClaimableFees(feeOwner, token);
await fees.claimFees(feeOwner, token);Stake
Staking is a single pool on Base. Ethereum's 15% arrives through a forwarder and Robinhood's through an escrow, so a Base staker earns from launches on all three chains. Rewards are paid in WETH; unstaking is a two-step unbonding with a 48-hour cooldown.
import { Cc0Staking } from '@cc0company/sdk';
import { parseEther } from 'viem';
const staking = new Cc0Staking({ walletClient });
await staking.stake(parseEther('1000')); // auto-approves if needed
const pos = await staking.getPosition(me); // staked / earned / unbonding
await staking.claimRewards(); // WETH to your walletGas-sponsored launches
launchTokenSponsored() and sponsorshipStatus() hit endpoints that send no CORS headers. They work server-side, from an agent, or from the cc0.company origin itself — a browser on a third-party domain is blocked and sponsorshipStatus() will read as inactive. Browser integrators on other domains must use the self-signed launchToken() path.
Your token on cc0.company — automatic
Every SDK launch is registered automatically: your token gets its page at cc0.company/token/{address} (live chart, swap, one-tap fee claim) and shows up in browse + search. The result's registered flag tells you it worked — a registry hiccup never fails the onchain launch. Opt out with register: false.
Integrating at the raw contract level without the SDK? Register your launch with the same call the SDK makes (this route sends CORS headers, so it works from any origin):
POST https://cc0.company/api/store/token-launches
{
"token_address": "0x…",
"chain": "robinhood", // "base" | "ethereum" | "robinhood"
"tx_hash": "0x…",
"protocol": "cc0strategy",
"name": "My Token",
"symbol": "MTK",
"image_url": "ipfs://…",
"creator_wallet": "0x…",
"split_type": "paired", // "standard" | "paired"
"paired_token": "0x…", // paired launches only
"paired_symbol": "AAPL",
"paired_decimals": 18
}Contracts
Standard suite
Paired suite
| Chain | Factory |
|---|---|
| Base | 0x6097FD2e8773cA8ED342aA8d9a999e05397e2705 |
| Robinhood | 0x65D667870E7B5b4b7113e5BaB255efE052cf3B36 |
Staking (Base)
- Staking pool:
0x38cE743b88c54eD1aF84816Ff596E518d16DFF95 - $cc0company:
0x67c5F00491c09cbCF6359f95690574E6106bb3CF
Full list with explorer links on Smart Contracts. Public agent skills — ready-to-paste recipes for launches, drops and x402 — live at github.com/cryptomfer/cc0company.
