Smart Contracts
Solidity 0.8.24/0.8.26, Cancun EVM, viaIR optimizer, Hardhat + OpenZeppelin UUPS proxies.
Architecture
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ PlatformConfig│◄────│ Factory │────►│ Registry │
│ (RBAC hub) │ │ (deployer) │ │ (tracking) │
└──────┬───────┘ └──────┬───────┘ └──────────────┘
│ │
│ fees, treasury, │ deploys
│ version, paused │
│ ▼
│ ┌──────────────┐ ┌──────────────┐
└───────────►│ Launch │────►│ MemeToken │
│(BondingCurve)│ │ (ERC-20) │
└──────┬───────┘ └──────────────┘
│
│ graduation
▼
┌──────────────┐
│LiquidityMgr │
│ → Adapter │
│ (Uni v4) │
└──────────────┘
PlatformConfig is the central RBAC hub. Factory deploys MemeToken + Launch pairs and snapshots platform config. BondingCurve (via Launch) is the AMM. Registry tracks all launches. LiquidityManager delegates graduation to registered adapters.
Contract Addresses
| Contract | Localhost (31337) | Testnet (46630) |
|---|---|---|
| PlatformConfig | 0x9fE4...a6e0 | 0xa0e5...C6eF |
| Factory | 0x0165...Eb8F | 0x8a99...2D40 |
| Registry | 0x2279...eBe6 | 0x65FA...4a3d |
| LiquidityManager | 0xDc64...cF6C9 | 0x0FC1...8030 |
| UniswapV4Adapter | 0x6101...D788 | 0xF6f6...1562 |
| PoolManager (Uni v4) | 0x5FbD...0aa3 | 0x0000...8A90 |
Import programmatically:
import { CONTRACT_ADDRESSES, getAddressesForChain } from "robin-launch/constants";
const addr = getAddressesForChain(46630);Factory.sol
Core deployer for meme tokens. UUPS upgradeable, initialized with PlatformConfig, reserve target, and curve supply defaults.
State Variables
| Name | Type | Description |
|---|---|---|
platformConfig | PlatformConfig | RBAC hub reference |
registry | IRegistry | Token tracking (set once) |
liquidityManager | address | Graduation handler (set once) |
defaultReserveTarget | uint256 | Fallback graduation target in wei |
defaultCurveSupply | uint256 | Fallback curve token supply |
TOKEN_CREATION_FEE | uint256 | 0.001 ether constant |
createToken
function createToken(
bytes32 platformId,
string name, string symbol, string description, string imageUri,
string website, string twitter, string telegram, string discord,
uint256 minTokensOut, // 0 = no initial buy
uint256 deadline, // block.timestamp + N
uint256 reserveTarget // 0 = use defaultReserveTarget
) external payable returns (address token, address launch)Deploys MemeToken → deploys Launch → transfers supply to Launch → registers in Registry → forwards creation fee. If minTokensOut > 0 and msg.value > TOKEN_CREATION_FEE, the excess buys tokens atomically and forwards them to the creator.
Modifiers: signupRequired(platformId) checks global + platform pause state. nonReentrant.
registerPlatform
Delegates to PlatformConfig.registerPlatform (with value: msg.value). Cost: 0.0005 ETH.
BondingCurve.sol
Constant-product bonding curve. Each token launch deploys a Launch contract that inherits from BondingCurve. All immutable state is set at construction from the Factory.
Immutables
| Name | Type | Description |
|---|---|---|
reserveTarget | uint256 | ETH threshold for graduation |
curveSupply | uint256 | Max tokens sold on curve |
platformId | bytes32 | Parent platform ID |
configVersion | uint32 | Snapshot at creation time |
tradingFeeBps | uint24 | Total trading fee (protocol + platform) |
creatorShareBps | uint24 | Creator's share of platform fee |
PROTOCOL_FEE_BPS | uint256 | 25 (0.25%) constant |
Virtual Reserves
// Initialised in constructor virtualEthReserves = reserveTarget / 4; virtualTokenReserves = (curveSupply * 5) / 4; k = virtualTokenReserves * virtualEthReserves;
The 25% virtual ETH and 125% virtual token reserves create a smooth price curve from the start — no infinite initial price.
buy
function buy(uint256 minTokensOut, uint256 deadline)
external payable whenNotPaused nonReentrantDeducts fee from msg.value, computes tokens via constant product, transfers tokens to buyer. If tokens would exceed remaining supply, caps the buy, refunds excess ETH, and triggers graduation.
sell
function sell(uint256 tokensIn, uint256 minEthOut, uint256 deadline)
external whenNotPaused nonReentrantFee Distribution Per Trade
Trade Amount
├── Net (after fee deduction)
└── Fee
├── Protocol Fee (0.25%) → protocolTreasury
├── Creator Share (%) of platformFee → creator
└── Platform Remainder → platformTreasuryGraduation
When realEthReserves ≥ reserveTarget or the buy exhausts remaining supply, the curve graduates:
graduated set to true
Remaining tokens + ETH reserves sent to LiquidityManager
LiquidityManager delegates to registered adapter (UniswapV4Adapter)
Uniswap v4 pool created with full-range liquidity
LP positions permanently locked (no withdraw function)
PlatformConfig.sol
Central RBAC and configuration hub. UUPS upgradeable, inherits OpenZeppelin AccessControlUpgradeable.
Structures
| Struct | Fields |
|---|---|
| Branding | name, logoUri, website, twitter, telegram, discord, docUrl, supportUrl, description |
| Fees | creationFee (uint256), tradingFeeBps (uint24), lpFee (uint24), creatorShareBps (uint24) |
| Stats | totalTokens, graduatedTokens, tradingVolume, totalFees, creatorRewards, protocolRewards, liquidityCreated, creationCount |
Fee Limits (global)
| Limit | Default | Meaning |
|---|---|---|
maxTradingFeeBps | 500 | Max 5% trading fee |
minTradingFeeBps | 25 | Min 0.25% (covers protocol fee) |
maxLpFee | 25000 | Max 2.5% LP fee tier |
maxCreatorShareBps | 5000 | Max 50% creator share |
LP fee tier must be exactly 5000 (0.5%), 10000 (1.0%), or 25000 (2.5%).
Fee Vaults (Pull Model)
protocolFeesAccrued; // global platformFeesAccrued[platformId]; // per platform creatorFeesAccrued[creatorAddress]; // per creator // Plus token-level accumulators for DEX fees
Registry.sol
Central on-chain registry tracking all launches, bonding curves, graduation status, and trade history.
| Function | Returns |
|---|---|
registerToken(...) | Stores launch info + creator mapping |
getLaunch(token) | LaunchInfo struct |
getAllLaunches() | LaunchInfo[] |
getCreatorTokens(creator) | address[] |
getGraduatedTokens() | address[] |
isValidBondingCurve(curve) | bool |
isTokenCreatedByFactory(token) | bool |
MemeToken.sol
Standard ERC-20 (OpenZeppelin) with extended metadata and fixed 1 billion token supply.
uint256 public constant TOTAL_SUPPLY = 1_000_000_000 * 10**18; address public immutable creator; uint256 public immutable creationTimestamp; // Plus: description, imageUri, website, twitter, telegram, discord
Deployed by Factory with msg.sender as initial owner. Full supply minted to Factory, then transferred to Launch.
LiquidityManager.sol
Decoupled coordinator that delegates liquidity provisioning to registered ILiquidityAdapter implementations. New DEX integrations only need a new adapter — no core contract changes.
UniswapV4Adapter
Implements ILiquidityAdapter. Creates Uniswap v4 pools with the configured LP fee tier and adds full-range liquidity on graduation. No LP withdrawal function exists — liquidity is permanently locked (anti-rug mechanism).
Roles & Access Control
| Role | Holder | Powers |
|---|---|---|
| DEFAULT_ADMIN_ROLE | Protocol owner | Global pause, adapter registration, fee boundaries, upgrade contracts, set registry/liquidityManager |
| PLATFORM_OWNER_ROLE | Per-platform | Update fees/treasury, pause platform, manage admins |
| PLATFORM_ADMIN_ROLE | Per-platform | Update branding |
| TREASURY_MANAGER_ROLE | Per-platform | Manage withdrawals (claim platform fees) |
Platform roles are derived: keccak256(abi.encodePacked("ROLE_NAME", platformId))
Events
| Event | Emitted By | Key Params |
|---|---|---|
TokenCreated | Factory | token, bondingCurve, creator, name, symbol |
Buy | BondingCurve | token, buyer, ethIn, tokensOut, fee, currentPrice |
Sell | BondingCurve | token, seller, tokensIn, ethOut, fee, currentPrice |
GraduationTriggered | BondingCurve | token, poolId, ethAmount, tokenAmount |
PlatformRegistered | PlatformConfig | platformId, owner, treasury |
PlatformFeesUpdated | PlatformConfig | platformId, tradingFeeBps, lpFee, creatorShareBps |
FeesDeposited | PlatformConfig | platformId, launch, creator, protocolFee, platformFee, creatorFee |
ReservesUpdated | Registry | token, realEthReserves, tokensSold, marketCap, totalVolume |
TokenGraduated | Registry | token, poolId |
Custom Errors
| Category | Errors |
|---|---|
| Access | OnlyOwner, OnlyFactory, OnlyBondingCurve, NotAuthorized, ZeroAddress, Reentrancy |
| Factory | InvalidCreationFee, FeeTransferFailed, LaunchNotFound |
| BondingCurve | CurveClosed, CurveAlreadyGraduated, InsufficientTokens, InsufficientEth, SlippageExceeded, DeadlineExpired |
| Platform | PlatformAlreadyRegistered, PlatformNotRegistered, PlatformPaused, GlobalPaused, FeeLimitExceeded |
| Liquidity | InvalidLPFee, PoolInitializationFailed, AddLiquidityFailed, AlreadyGraduated, NoActiveAdapter |
| Treasury | Paused, InsufficientBalance, TransferFailed, ZeroAmount, NoFeesToClaim, InvalidFeeSplit |
Configuration Versioning
When a platform owner updates fees or treasury, the platform's version increments. The Factory snapshots the current version into each new Launch contract, so active bonding curves are immutable regardless of later config changes. Changing platform fees never affects existing launches.