Technical Specification

Contract Overview

The MEME Bonding Curve contract facilitates the initial token distribution and liquidity bootstrapping for the MEME token ecosystem. It implements a mathematical bonding curve for price discovery and automatically migrates liquidity to Uniswap V4 upon reaching the fundraising target.

Contract Architecture

Core Contracts

  1. MEMEBondingCurve.sol - Main bonding curve logic

  2. BondingCurveMath.sol - Price calculation library

  3. UniswapV4Migrator.sol - Handles DEX migration

  4. MEMEToken.sol - Modified to support bonding curve

Key Interfaces

interface IMEMEBondingCurve {
    // Events
    event TokensPurchased(
        address indexed buyer,
        uint256 usdcAmount,
        uint256 memeAmount,
        uint256 newPrice
    );
    event TargetReached(uint256 totalRaised, uint256 totalSold);
    event LiquidityMigrated(
        bytes32 poolId,
        uint256 memeAmount,
        uint256 usdcAmount
    );

    // Core functions
    function buyTokens(uint256 usdcAmount) external returns (uint256 memeAmount);
    function getCurrentPrice() external view returns (uint256);
    function getQuote(uint256 usdcAmount) external view returns (uint256 memeAmount);
    function migrateToUniswap() external;
}

State Variables

contract MEMEBondingCurve {
    // Token contracts
    IERC20 public immutable USDC;
    IERC20 public immutable MEME;

    // Sale parameters
    uint256 public constant TOTAL_SALE_SUPPLY = 100_000_000e18; // 100M MEME
    uint256 public constant TARGET_RAISE = 750_000e6; // 750K USDC (6 decimals)
    uint256 public constant MIN_PURCHASE = 10e6; // $10 minimum
    uint256 public constant MAX_PURCHASE = 50_000e6; // $50K maximum

    // Curve parameters
    uint256 public constant INITIAL_PRICE = 1e15; // 0.001 USDC per MEME (scaled)
    uint256 public constant CURVE_COEFFICIENT = 1e10; // Curve steepness

    // Sale state
    uint256 public totalSold;
    uint256 public totalRaised;
    bool public saleActive;
    bool public targetReached;
    bool public migrated;

    // User tracking
    mapping(address => uint256) public userPurchased;
    mapping(address => uint256) public userSpent;
    mapping(address => uint256) public lastPurchaseTime;

    // Security
    uint256 public constant PURCHASE_COOLDOWN = 60; // 1 minute between purchases
    uint256 public constant MAX_PER_WALLET = 100_000e6; // $100K max per wallet
}

Price Calculation

Sigmoid Curve Implementation

library BondingCurveMath {
    using PRBMathUD60x18 for uint256;

    function calculatePrice(
        uint256 totalSold,
        uint256 initialPrice,
        uint256 coefficient
    ) internal pure returns (uint256) {
        // Sigmoid curve: P = P_min + (P_max - P_min) / (1 + e^(-k(x - x_mid)))
        uint256 P_MIN = initialPrice;
        uint256 P_MAX = initialPrice * 15; // 15x max price
        uint256 X_MID = 50_000_000e18; // Midpoint at 50M tokens

        // Calculate exponential component
        int256 exponent = -int256(coefficient * (totalSold - X_MID) / 1e18);
        uint256 expValue = uint256(exp(exponent));

        // Calculate final price
        uint256 price = P_MIN + ((P_MAX - P_MIN) * 1e18) / (1e18 + expValue);
        return price;
    }

    function calculateTokensOut(
        uint256 usdcIn,
        uint256 totalSold,
        uint256 initialPrice,
        uint256 coefficient
    ) internal pure returns (uint256 tokensOut, uint256 avgPrice) {
        // Numerical integration for exact calculation
        uint256 steps = 100; // Integration steps
        uint256 stepSize = usdcIn / steps;
        uint256 currentSold = totalSold;
        tokensOut = 0;

        for (uint256 i = 0; i < steps; i++) {
            uint256 currentPrice = calculatePrice(
                currentSold,
                initialPrice,
                coefficient
            );
            uint256 tokensInStep = (stepSize * 1e18) / currentPrice;
            tokensOut += tokensInStep;
            currentSold += tokensInStep;
        }

        avgPrice = (usdcIn * 1e18) / tokensOut;
        return (tokensOut, avgPrice);
    }
}

Core Functions

Buy Tokens

function buyTokens(uint256 usdcAmount) external nonReentrant whenNotPaused {
    require(saleActive, "Sale not active");
    require(!targetReached, "Target reached");
    require(usdcAmount >= MIN_PURCHASE, "Below minimum");
    require(usdcAmount <= MAX_PURCHASE, "Above maximum");

    // Cooldown check
    require(
        block.timestamp >= lastPurchaseTime[msg.sender] + PURCHASE_COOLDOWN,
        "Cooldown active"
    );

    // Wallet limit check
    require(
        userSpent[msg.sender] + usdcAmount <= MAX_PER_WALLET,
        "Wallet limit exceeded"
    );

    // Calculate tokens out
    (uint256 memeAmount, uint256 avgPrice) = BondingCurveMath.calculateTokensOut(
        usdcAmount,
        totalSold,
        INITIAL_PRICE,
        CURVE_COEFFICIENT
    );

    // Check if we would exceed sale supply
    require(totalSold + memeAmount <= TOTAL_SALE_SUPPLY, "Exceeds sale supply");

    // Transfer USDC from buyer
    USDC.safeTransferFrom(msg.sender, address(this), usdcAmount);

    // Update state
    totalSold += memeAmount;
    totalRaised += usdcAmount;
    userPurchased[msg.sender] += memeAmount;
    userSpent[msg.sender] += usdcAmount;
    lastPurchaseTime[msg.sender] = block.timestamp;

    // Transfer MEME to buyer
    MEME.safeTransfer(msg.sender, memeAmount);

    // Emit event
    emit TokensPurchased(msg.sender, usdcAmount, memeAmount, avgPrice);

    // Check if target reached
    if (totalRaised >= TARGET_RAISE) {
        targetReached = true;
        saleActive = false;
        emit TargetReached(totalRaised, totalSold);
    }
}

Uniswap V4 Migration

function migrateToUniswap() external nonReentrant {
    require(targetReached, "Target not reached");
    require(!migrated, "Already migrated");

    migrated = true;

    // Calculate liquidity amounts
    uint256 memeForLiquidity = TOTAL_SALE_SUPPLY; // Match sold amount
    uint256 usdcForLiquidity = totalRaised;

    // Approve tokens to position manager
    MEME.approve(address(positionManager), memeForLiquidity);
    USDC.approve(address(positionManager), usdcForLiquidity);

    // Create pool if needed
    PoolKey memory poolKey = PoolKey({
        currency0: Currency.wrap(address(USDC)),
        currency1: Currency.wrap(address(MEME)),
        fee: 10000, // 1% fee
        tickSpacing: 200,
        hooks: IHooks(address(0))
    });

    // Initialize pool at final bonding curve price
    uint256 finalPrice = BondingCurveMath.calculatePrice(
        totalSold,
        INITIAL_PRICE,
        CURVE_COEFFICIENT
    );
    uint160 sqrtPriceX96 = calculateSqrtPriceX96(finalPrice);

    poolManager.initialize(poolKey, sqrtPriceX96);

    // Add liquidity as full range
    IPositionManager.MintParams memory params = IPositionManager.MintParams({
        poolKey: poolKey,
        tickLower: -887200, // Full range
        tickUpper: 887200,
        liquidity: calculateLiquidity(memeForLiquidity, usdcForLiquidity),
        amount0Desired: usdcForLiquidity,
        amount1Desired: memeForLiquidity,
        amount0Min: 0,
        amount1Min: 0,
        recipient: treasury,
        deadline: block.timestamp,
        salt: bytes32(0)
    });

    (uint256 tokenId, , , ) = positionManager.mint(params);

    emit LiquidityMigrated(
        PoolId.unwrap(poolKey.toId()),
        memeForLiquidity,
        usdcForLiquidity
    );
}

Security Features

Access Control

contract MEMEBondingCurve is Ownable, Pausable, ReentrancyGuard {
    // Emergency functions
    function pause() external onlyOwner {
        _pause();
    }

    function unpause() external onlyOwner {
        _unpause();
    }

    function emergencyWithdraw() external onlyOwner {
        require(paused(), "Not paused");
        // Only after 7 days of pause
        require(block.timestamp > pausedAt + 7 days, "Too early");

        // Refund mechanism would go here
    }
}

Anti-Bot Measures

modifier antibotProtection() {
    // Check gas price
    require(tx.gasprice <= maxGasPrice, "Gas price too high");

    // Check origin
    require(tx.origin == msg.sender, "No contracts");

    // Rate limiting is handled by cooldown
    _;
}

View Functions

// Get current price
function getCurrentPrice() external view returns (uint256) {
    return BondingCurveMath.calculatePrice(
        totalSold,
        INITIAL_PRICE,
        CURVE_COEFFICIENT
    );
}

// Get quote for USDC amount
function getQuote(uint256 usdcAmount) external view returns (
    uint256 memeAmount,
    uint256 avgPrice,
    uint256 priceImpact
) {
    (memeAmount, avgPrice) = BondingCurveMath.calculateTokensOut(
        usdcAmount,
        totalSold,
        INITIAL_PRICE,
        CURVE_COEFFICIENT
    );

    uint256 currentPrice = this.getCurrentPrice();
    priceImpact = ((avgPrice - currentPrice) * 10000) / currentPrice;

    return (memeAmount, avgPrice, priceImpact);
}

// Get sale stats
function getSaleStats() external view returns (
    uint256 sold,
    uint256 raised,
    uint256 remaining,
    uint256 progress,
    uint256 currentPrice
) {
    sold = totalSold;
    raised = totalRaised;
    remaining = TOTAL_SALE_SUPPLY - totalSold;
    progress = (raised * 10000) / TARGET_RAISE;
    currentPrice = this.getCurrentPrice();
}

Testing Strategy

Unit Tests

  1. Price calculation accuracy

  2. Token amount calculations

  3. Boundary conditions

  4. Security features

  5. State transitions

Integration Tests

  1. Full purchase flow

  2. Uniswap migration

  3. Multi-user scenarios

  4. Gas optimization

  5. Edge cases

Fuzzing

  1. Random purchase amounts

  2. Rapid sequential purchases

  3. Price manipulation attempts

  4. Overflow/underflow checks

Gas Optimization

  1. Immutable Variables: Use for constants

  2. Storage Packing: Optimize struct layout

  3. Batch Operations: Where possible

  4. Minimal Storage Writes: Cache calculations

  5. Efficient Math: Use optimized libraries

Deployment Steps

  1. Deploy MEME token (if not exists)

  2. Deploy BondingCurveMath library

  3. Deploy MEMEBondingCurve

  4. Transfer MEME tokens to curve

  5. Configure parameters

  6. Run final tests

  7. Activate sale

Post-Deployment Monitoring

  1. Price Tracking: Monitor curve progression

  2. Volume Analysis: Track purchase patterns

  3. Wallet Distribution: Ensure fair distribution

  4. Bot Detection: Watch for suspicious activity

  5. System Health: Monitor gas usage and failures


This technical specification should be reviewed by security auditors before implementation.

Last updated