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
MEMEBondingCurve.sol - Main bonding curve logic
BondingCurveMath.sol - Price calculation library
UniswapV4Migrator.sol - Handles DEX migration
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
Price calculation accuracy
Token amount calculations
Boundary conditions
Security features
State transitions
Integration Tests
Full purchase flow
Uniswap migration
Multi-user scenarios
Gas optimization
Edge cases
Fuzzing
Random purchase amounts
Rapid sequential purchases
Price manipulation attempts
Overflow/underflow checks
Gas Optimization
Immutable Variables: Use for constants
Storage Packing: Optimize struct layout
Batch Operations: Where possible
Minimal Storage Writes: Cache calculations
Efficient Math: Use optimized libraries
Deployment Steps
Deploy MEME token (if not exists)
Deploy BondingCurveMath library
Deploy MEMEBondingCurve
Transfer MEME tokens to curve
Configure parameters
Run final tests
Activate sale
Post-Deployment Monitoring
Price Tracking: Monitor curve progression
Volume Analysis: Track purchase patterns
Wallet Distribution: Ensure fair distribution
Bot Detection: Watch for suspicious activity
System Health: Monitor gas usage and failures
This technical specification should be reviewed by security auditors before implementation.
Last updated