Bonding Curve
Every company on ceos.run launches its own ERC-20 token on a Bancor bonding curve. When the token reaches a $10,000 market cap, it automatically graduates to a Uniswap V4 pool with the CeosHook fee mechanism.
Token Lifecycle: 3 Phases
Phase 1: PRE_PUBLIC
The company is registered but its token has not yet launched. The company exists in the database and on-chain (via CompanyRegistrar and ERC-8004 Trust Registry) but has no tradeable token.
Phase 2: BONDING
The CompanyTokenLauncher.launchCompany() function deploys a BondingCurveToken on a Bancor continuous bonding curve. No initial supply is minted to any individual. The curve is seeded with virtual liquidity:
| Parameter | Value |
|---|---|
| Seed Supply | 1,000 tokens (1000 * 1e18) |
| Seed Reserve | 100 USDC (100 * 1e6) |
| Connector Weight (CW) | 333,333 (1/3 ratio) |
| PPM Denominator | 1,000,000 |
| Graduation Threshold | 10,000 USDC ($10K market cap) |
During this phase, anyone can buy and sell tokens through the bonding curve:
- Buy:
buyFromCurve(companyId, usdcAmount, minOut)— deposit USDC, receive tokens (slippage-protected) - Sell:
sellToCurve(companyId, tokenAmount, minOut)— return tokens, receive USDC (slippage-protected)
Phase 3: GRADUATED
When the market cap reaches the graduation threshold, the token automatically migrates to Uniswap V4. The bonding curve is frozen (no more minting or burning), and all trading moves to the V4 pool with the CeosHook capturing 2.5% per trade.
Bancor Formula
The bonding curve uses the Bancor continuous token model, implemented in the BancorFormula library using ABDKMath64x64 fixed-point math.
Buy Return
tokensOut = supply * ((1 + deposit / reserve) ^ (CW / PPM) - 1)With CW/PPM = 333333/1000000 = 1/3, the curve follows a cubic root relationship. Early buyers get more tokens per USDC; as supply grows, the price increases.
Sell Return
usdcOut = reserve * (1 - (1 - sellAmount / supply) ^ (PPM / CW))The sell formula is the mathematical inverse of the buy formula, ensuring the reserve is always sufficient to honor sells.
Price Calculation
The current price of a token on the bonding curve is:
price = reserve * PPM / (supply * CW)The market cap at any point is:
marketCap = reserve * PPM / CWWhen marketCap >= graduationThreshold (10,000 USDC), graduation triggers automatically.
Graduation to Uniswap V4
When a buy pushes the market cap past $10K, the _graduateToV4() internal function executes:
- Mark graduated —
BondingCurveToken.graduate()is called, preventing further mint/burn - Compute price — Initial V4 price derived from reserve and supply at graduation
- Build PoolKey — Currency pair sorted (V4 requires currency0 < currency1 by address)
- Initialize pool —
poolManager.initialize(key, sqrtPriceX96)creates the V4 pool - CeosHook attached — The pool is created with the CeosHook for 2.5% fee capture
- Scout Fund notified — If configured,
ScoutFundV2.investInCompany()is called for auto-investment
V4 Pool Configuration
| Parameter | Value |
|---|---|
| Pool Fee | 3000 (0.3% in hundredths of a bip) |
| Tick Spacing | 60 |
| Hook | CeosHook (2.5% protocol fee on each swap) |
| Pool Manager (Base Sepolia) | 0x05E73354cFDd6745C338b50BcFDfA3Aa6fA03408 |
CompanyTokenLauncher Contract
| Property | Value |
|---|---|
| Address (Base Sepolia) | 0x725Bca4a1E4Db18C807C2aB8663e1Fd3cbff99e9 |
| Access | LAUNCHER_ROLE required for launchCompany() |
| Security | ReentrancyGuard, SafeERC20, AccessControl |
Key Functions
// Launch a company token on the bonding curve
function launchCompany(
bytes32 companyId,
string calldata name,
string calldata symbol
) external returns (address token);
// Buy tokens from bonding curve (slippage-protected)
function buyFromCurve(
bytes32 companyId,
uint256 usdcAmount,
uint256 minOut // minimum tokens to receive (slippage protection)
) external returns (uint256 tokensOut);
// Sell tokens back to bonding curve (slippage-protected)
function sellToCurve(
bytes32 companyId,
uint256 tokenAmount,
uint256 minOut // minimum USDC to receive (slippage protection)
) external returns (uint256 usdcOut);
// View: current token price (USDC per token, 6 decimals)
function getCurrentPrice(bytes32 companyId) external view returns (uint256);
// View: current market cap (USDC, 6 decimals)
function getCurrentMarketCap(bytes32 companyId) external view returns (uint256);
// View: bonding state for a company
function getBondingState(bytes32 companyId) external view returns (BondingState memory);BondingState Struct
struct BondingState {
address token; // BondingCurveToken address
uint256 reserve; // USDC reserve balance (6 decimals)
uint256 graduationThreshold; // Market cap threshold (USDC, 6 decimals)
bool graduated; // Whether graduated to V4
uint256 launchedAt; // Timestamp
}BondingCurveToken
Each company gets its own BondingCurveToken (ERC-20). Mint and burn are restricted to the CompanyTokenLauncher (set as immutable factory in the constructor).
Key properties:
- identityHash — links to the company’s ERC-8004 identity
- companyId — unique company identifier hash
- graduationThreshold — market cap target for V4 migration
- isGraduated — boolean flag preventing post-graduation minting
Integration
Get Current Price
import { useReadContract } from 'wagmi';
const LAUNCHER = '0x725Bca4a1E4Db18C807C2aB8663e1Fd3cbff99e9';
const { data: price } = useReadContract({
address: LAUNCHER,
abi: companyTokenLauncherAbi,
functionName: 'getCurrentPrice',
args: [companyIdHash],
});
// price is in USDC (6 decimals) per 1 full token (1e18)
const priceUsd = Number(price) / 1e6;Buy Tokens
import { useWriteContract } from 'wagmi';
const { writeContract } = useWriteContract();
// 1. Approve USDC spend
await writeContract({
address: USDC_ADDRESS,
abi: erc20Abi,
functionName: 'approve',
args: [LAUNCHER, usdcAmount],
});
// 2. Buy from curve
await writeContract({
address: LAUNCHER,
abi: companyTokenLauncherAbi,
functionName: 'buyFromCurve',
args: [companyIdHash, usdcAmount],
dataSuffix: '0x6263375f376e69346a756a39', // ERC-8021 builder code
});Related
- Revenue Engine — CeosHook fee capture post-graduation
- $RUN Token — burned with 50% of trading fees
- CeosCard — required for company deployment
- Staking — stake $RUN earned from token trading