Skip to Content
Smart ContractsBondingCurveToken & CompanyTokenLauncher

BondingCurveToken & CompanyTokenLauncher

The company token system has two phases: a Bancor bonding curve for price discovery, followed by automatic graduation to a Uniswap V4 pool when market cap reaches the threshold.

Contracts

ContractAddressRole
CompanyTokenLauncher0x725Bca4a1E4Db18C807C2aB8663e1Fd3cbff99e9Factory, bonding curve management, V4 graduation
BondingCurveTokenPer-company (EIP-1167)ERC-20 token with factory-restricted mint/burn
BancorFormulaLibraryConnector weight math for buy/sell price calculation

Bonding Curve Constants

ParameterValueDescription
Connector Weight (CW)333,333Bancor weight numerator (1/3)
PPM1,000,000Parts per million denominator
Seed Supply1,000 tokens (1e21 wei)Initial virtual liquidity
Seed Reserve100 USDC (1e8 wei)Initial virtual reserve
Graduation Threshold10,000 USDCMarket cap trigger for V4 migration

Token Lifecycle

Phase 1 — Bonding Curve

  1. A company is launched via launchCompany(). This deploys a new BondingCurveToken instance and seeds the curve with 1,000 tokens and 100 USDC virtual reserve.
  2. Anyone can buy tokens via buyFromCurve() using USDC. The Bancor formula calculates the token amount.
  3. Anyone can sell tokens back via sellToCurve(). The formula calculates the USDC return.
  4. Price rises with demand according to the Bancor power curve.

Phase 2 — V4 Graduation

  1. When market cap reaches graduationThreshold (default $10K), the token auto-graduates.
  2. The BondingCurveToken is marked as graduated (mint/burn disabled permanently).
  3. A Uniswap V4 pool is initialized with the accumulated reserve as liquidity.
  4. If a ScoutFundV2 is configured, it auto-invests in the new pool.
  5. Post-graduation, the token trades freely on Uniswap V4 with the CeosHook fee.

BondingCurveToken Interface

/// @notice The factory contract authorized to mint/burn (immutable, set in constructor) function factory() external view returns (address); /// @notice The ERC-8004 identity hash this token represents function identityHash() external view returns (bytes32); /// @notice Company ID hash (zero for legacy agent tokens) function companyId() external view returns (bytes32); /// @notice Market cap threshold for V4 graduation (USDC, 6 decimals) function graduationThreshold() external view returns (uint256); /// @notice Whether this token has graduated to a V4 pool function isGraduated() external view returns (bool); /// @notice Mint tokens (factory only, reverts if graduated) function mint(address to, uint256 amount) external; /// @notice Burn tokens from holder (factory only, no allowance needed, reverts if graduated) function burnFrom(address from, uint256 amount) external; /// @notice Initialize company-specific fields (factory only, once) function initializeCompany(bytes32 _companyId, uint256 _graduationThreshold) external; /// @notice Mark token as graduated (factory only) function graduate() external;

The burnFrom function bypasses ERC-20 allowance by design. Only the immutable factory (set in the constructor) can call it, and the factory address cannot be changed after deployment.

CompanyTokenLauncher Interface

Launch

/// @notice Deploy a company token on a bonding curve. /// @param companyId Unique identifier (keccak256 of company slug) /// @param name Token name (e.g., "ZeroToOne") /// @param symbol Token symbol (e.g., "ZTO") /// @return token The deployed BondingCurveToken address function launchCompany( bytes32 companyId, string calldata name, string calldata symbol ) external returns (address token);

Requires LAUNCHER_ROLE. Duplicate companyId values are rejected.

Trading

/// @notice Buy company tokens from the bonding curve using USDC. /// @param companyId Company identifier /// @param usdcAmount Amount of USDC to spend (6 decimals) /// @param minOut Minimum tokens to receive (slippage protection) /// @return tokensOut Number of tokens received (18 decimals) function buyFromCurve( bytes32 companyId, uint256 usdcAmount, uint256 minOut ) external returns (uint256 tokensOut); /// @notice Sell company tokens back to the bonding curve for USDC. /// @param companyId Company identifier /// @param tokenAmount Amount of tokens to sell (18 decimals) /// @param minOut Minimum USDC to receive (slippage protection) /// @return usdcOut Amount of USDC received (6 decimals) function sellToCurve( bytes32 companyId, uint256 tokenAmount, uint256 minOut ) external returns (uint256 usdcOut);

Views

/// @notice Current token price on the bonding curve. /// price = reserve * PPM / (supply * CW) /// @return price USDC per token (6 decimals, scaled to 1e18 token) function getCurrentPrice(bytes32 companyId) external view returns (uint256); /// @notice Current market cap on the bonding curve. /// marketCap = reserve * PPM / CW /// @return marketCap In USDC (6 decimals) function getCurrentMarketCap(bytes32 companyId) external view returns (uint256); /// @notice Get bonding curve state for a company. function getBondingState(bytes32 companyId) external view returns (BondingState memory); /// @notice Get the V4 pool record for a graduated company. function getCompanyPool(bytes32 companyId) external view returns (CompanyPool memory); /// @notice Total number of companies that have launched tokens. function totalCompanies() external view returns (uint256);

Structs

struct BondingState { address token; // BondingCurveToken address uint256 reserve; // USDC reserve balance (6 decimals) uint256 graduationThreshold; // Market cap threshold for V4 graduation bool graduated; // Whether graduated to V4 uint256 launchedAt; // Timestamp } struct CompanyPool { address token; PoolId poolId; uint256 initialSupply; uint256 initialPriceUsdc; uint256 launchedAt; }

Price Formula

The Bancor formula with connector weight 1/3:

Buy: tokensOut = supply * ((1 + usdcAmount / reserve) ^ (CW/PPM) - 1) Sell: usdcOut = reserve * (1 - (1 - tokenAmount / supply) ^ (PPM/CW)) Spot price: price = reserve * PPM / (supply * CW) Market cap: marketCap = reserve * PPM / CW

The connector weight of 1/3 means the price increases sub-linearly with supply — early buyers get better prices, creating natural demand incentives.

Graduation

When a buyFromCurve transaction pushes marketCap >= graduationThreshold, the internal _graduateToV4 function:

  1. Marks the BondingCurveToken as graduated (disables mint/burn permanently).
  2. Computes sqrtPriceX96 from the graduation price and currency sort order.
  3. Initializes a Uniswap V4 pool via poolManager.initialize().
  4. Stores the V4 pool record in companyPools[companyId].
  5. If scoutFund is configured, calls investInCompany() (non-blocking with try/catch).

Events

event BondingCurveDeployed(bytes32 indexed companyId, address indexed token, uint256 graduationThreshold); event TokenBought(bytes32 indexed companyId, address indexed buyer, uint256 usdcIn, uint256 tokensOut); event TokenSold(bytes32 indexed companyId, address indexed seller, uint256 tokensIn, uint256 usdcOut); event CompanyGraduated(bytes32 indexed companyId, address token, PoolId poolId, uint256 marketCap); event PoolInitialized(bytes32 indexed companyId, PoolId indexed poolId, address token, address usdc, uint160 sqrtPriceX96); event ScoutInvestFailed(bytes32 indexed companyId, address token, bytes reason);

Roles

RolePermission
LAUNCHER_ROLECall launchCompany()
DEFAULT_ADMIN_ROLEConfig setters (setPoolFee, setGraduationThreshold, setCeosHook, setScoutFund)

Security

  • ReentrancyGuard on launchCompany, buyFromCurve, sellToCurve
  • SafeERC20 for all USDC operations
  • Duplicate companyId prevention via mapping check
  • onlyFactory modifier on BondingCurveToken prevents unauthorized minting
  • onlyNotGraduated modifier prevents post-graduation mint/burn
  • Non-blocking ScoutFund integration (try/catch) prevents graduation failure