Разработка платформы запуска мемкоинов
Pump.fun обработал более $1B транзакций за первый год работы. Ключевой insight команды: барьер для запуска токена был слишком высоким (деплой контракта, создание LP, листинг), а механизм накачки через bonding curve — предсказуемым и понятным пользователям. Результат — machine for token launches, которая генерирует миллионы в protocol revenue ежемесячно.
Платформа подобного рода технически нетривиальна: bonding curve со специфической математикой, автоматический переход на DEX при достижении порога ликвидности, anti-rug механизмы, и всё это должно работать за секунды при высокой конкуренции.
Bonding curve: математика и реализация
Константная product curve (упрощённый Pump.fun)
Pump.fun использует виртуальный AMM с константным произведением. При запуске токен не имеет реальной ликвидности — есть виртуальные резервы, которые задают начальную цену.
contract BondingCurve {
uint256 public constant VIRTUAL_SOL_RESERVE = 30_000_000_000; // 30 SOL виртуальных
uint256 public constant VIRTUAL_TOKEN_RESERVE = 1_073_000_000 * 10**6; // 1.073B токенов
uint256 public constant TOTAL_SUPPLY = 1_000_000_000 * 10**6;
uint256 public constant GRADUATION_THRESHOLD = 85_000_000_000; // 85 SOL собрано
uint256 public realSolReserve; // фактически внесённый SOL
uint256 public realTokenReserve; // токены в кривой
// k = (virtual_sol + real_sol) * (virtual_token + real_token) = const
function buy(uint256 solIn) external payable returns (uint256 tokensOut) {
require(msg.value == solIn, "Value mismatch");
require(!graduated, "Already on DEX");
uint256 virtualSol = VIRTUAL_SOL_RESERVE + realSolReserve;
uint256 virtualToken = VIRTUAL_TOKEN_RESERVE - (TOTAL_SUPPLY - realTokenReserve);
// Constant product: k = virtualSol * virtualToken
// После покупки: (virtualSol + solIn) * (virtualToken - tokensOut) = k
// tokensOut = virtualToken - k / (virtualSol + solIn)
uint256 k = virtualSol * virtualToken;
tokensOut = virtualToken - (k / (virtualSol + solIn));
require(tokensOut <= realTokenReserve, "Not enough tokens");
realSolReserve += solIn;
realTokenReserve -= tokensOut;
token.transfer(msg.sender, tokensOut);
// Проверяем graduation
if (realSolReserve >= GRADUATION_THRESHOLD) {
_graduate();
}
emit TokensPurchased(msg.sender, solIn, tokensOut, currentPrice());
}
function currentPrice() public view returns (uint256) {
uint256 virtualSol = VIRTUAL_SOL_RESERVE + realSolReserve;
uint256 virtualToken = VIRTUAL_TOKEN_RESERVE - (TOTAL_SUPPLY - realTokenReserve);
// price in SOL per token (lamports)
return (virtualSol * 10**6) / virtualToken;
}
}
Виртуальные резервы — ключевой элемент. Без них начальная цена при нулевой ликвидности была бы 0. Виртуальные резервы создают искусственную «глубину» кривой, формируя стартовую цену и контролируя price impact первых покупок.
Graduation: переход на Raydium/Uniswap
Когда platforma собирает достаточно SOL/ETH — токен «graduates»: контракт автоматически создаёт LP пул на DEX и добавляет ликвидность.
function _graduate() internal {
graduated = true;
uint256 solForLiquidity = realSolReserve; // весь собранный SOL
uint256 tokensForLiquidity = realTokenReserve; // оставшиеся токены
// Создаём LP на Uniswap V2 (или Raydium на Solana)
IUniswapV2Router router = IUniswapV2Router(ROUTER_ADDRESS);
token.approve(address(router), tokensForLiquidity);
(uint amountToken, uint amountETH, uint liquidity) = router.addLiquidityETH{
value: solForLiquidity
}(
address(token),
tokensForLiquidity,
tokensForLiquidity * 99 / 100, // 1% slippage
solForLiquidity * 99 / 100,
address(0), // LP токены на address(0) — burn ликвидности
block.timestamp + 300
);
// Сжигаем LP токены — ликвидность permanent, нельзя rug pull
emit Graduated(address(token), amountToken, amountETH, liquidity);
}
Burn LP токенов при graduation — критический anti-rug механизм. Создатель токена не может вывести ликвидность и сбежать. Это главное доверительное преимущество Pump.fun над самостоятельным запуском.
Solana: почему большинство meme платформ там
Pump.fun работает на Solana не случайно:
- Транзакция: ~$0.0001 vs $0.5-5 на Ethereum mainnet
- Finality: ~400ms vs 12+ секунд
- При высокочастотных launch событиях (сотни токенов в час) — это решающее UX преимущество
Solana Anchor framework для контрактов:
use anchor_lang::prelude::*;
use anchor_spl::token::{self, Mint, Token, TokenAccount};
#[program]
pub mod pump_clone {
use super::*;
pub fn create_token(
ctx: Context<CreateToken>,
name: String,
symbol: String,
uri: String,
total_supply: u64,
) -> Result<()> {
// Минтим все токены в bonding curve vault
token::mint_to(
CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
token::MintTo {
mint: ctx.accounts.mint.to_account_info(),
to: ctx.accounts.bonding_curve_vault.to_account_info(),
authority: ctx.accounts.mint_authority.to_account_info(),
},
&[&[b"mint_authority", &[ctx.bumps.mint_authority]]],
),
total_supply,
)?;
// Инициализируем bonding curve account
let curve = &mut ctx.accounts.bonding_curve;
curve.total_supply = total_supply;
curve.virtual_sol_reserves = 30_000_000_000; // 30 SOL
curve.virtual_token_reserves = total_supply;
curve.real_sol_reserves = 0;
curve.real_token_reserves = total_supply;
curve.graduated = false;
curve.creator = ctx.accounts.creator.key();
emit!(TokenCreated {
mint: ctx.accounts.mint.key(),
creator: ctx.accounts.creator.key(),
name,
symbol,
uri,
});
Ok(())
}
pub fn buy(ctx: Context<Buy>, sol_amount: u64, min_tokens: u64) -> Result<()> {
let curve = &mut ctx.accounts.bonding_curve;
require!(!curve.graduated, ErrorCode::AlreadyGraduated);
let tokens_out = curve.calculate_buy(sol_amount)?;
require!(tokens_out >= min_tokens, ErrorCode::SlippageExceeded);
// Transfer SOL from buyer to vault
anchor_lang::system_program::transfer(
CpiContext::new(
ctx.accounts.system_program.to_account_info(),
anchor_lang::system_program::Transfer {
from: ctx.accounts.buyer.to_account_info(),
to: ctx.accounts.sol_vault.to_account_info(),
},
),
sol_amount,
)?;
// Transfer tokens from vault to buyer
token::transfer(
CpiContext::new_with_signer(/* ... */),
tokens_out,
)?;
curve.real_sol_reserves += sol_amount;
curve.real_token_reserves -= tokens_out;
// Проверяем graduation
if curve.real_sol_reserves >= GRADUATION_SOL_THRESHOLD {
ctx.accounts.bonding_curve.graduated = true;
// Вызов Raydium CPI для создания LP...
}
Ok(())
}
}
Anti-rug и fair launch механизмы
Creator lock
// Creator не может продать в первые X блоков/минут
mapping(address => uint256) public creatorLockExpiry;
function createToken(...) external {
// ...
creatorLockExpiry[newToken] = block.timestamp + 24 hours;
}
// Override transfer для creator
function _beforeTokenTransfer(address from, address to, uint256 amount) internal override {
if (from == tokenCreator[address(this)]) {
require(block.timestamp >= creatorLockExpiry[address(this)], "Creator locked");
}
}
Max buy per wallet
Ограничение снижает premine-сценарии когда создатель скупает большую часть supply через bonding curve до публикации:
uint256 public constant MAX_BUY_PERCENT = 200; // 2% total supply
uint256 public constant MAX_BUY_AMOUNT = TOTAL_SUPPLY * MAX_BUY_PERCENT / 10000;
mapping(address => uint256) public totalBought;
function buy(uint256 solIn) external {
// ...
require(totalBought[msg.sender] + tokensOut <= MAX_BUY_AMOUNT, "Max buy exceeded");
totalBought[msg.sender] += tokensOut;
}
Revenue модель платформы
Платформа зарабатывает на каждой транзакции в bonding curve. Pump.fun берёт 1% от каждой покупки/продажи. При $1M дневного объёма — $10k дневной revenue только от trading fee. Дополнительно — graduation fee при листинге на DEX.
uint256 public constant PLATFORM_FEE_BPS = 100; // 1%
address public immutable feeRecipient;
function buy(uint256 solIn) external payable {
uint256 platformFee = (solIn * PLATFORM_FEE_BPS) / 10000;
uint256 effectiveSolIn = solIn - platformFee;
// platformFee отправляется на feeRecipient
payable(feeRecipient).transfer(platformFee);
// Остаток идёт в bonding curve
_processBuy(effectiveSolIn);
}
Фронтенд: real-time UX
Пользователи ожидают мгновенный фидбек: chart обновляется после каждого swap, activity feed показывает буквально последние 10 транзакций.
WebSocket для real-time. Subscribe на on-chain события через Helius (Solana) или Alchemy (EVM). При каждом TokensPurchased событии — обновить chart, добавить в activity feed.
// Real-time price updates via WebSocket
const ws = new WebSocket('wss://mainnet.helius-rpc.com/?api-key=...')
ws.send(JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'logsSubscribe',
params: [
{ mentions: [PROGRAM_ID] },
{ commitment: 'confirmed' }
]
}))
ws.onmessage = (event) => {
const { result } = JSON.parse(event.data)
if (result?.value?.logs) {
const parsed = parsePurchaseEvent(result.value.logs)
if (parsed) updateChart(parsed)
}
}
OHLCV chart. Для каждого токена строим OHLCV из transaction history. Aggre по 1-минутным свечам. TradingView Lightweight Charts — стандарт для crypto проектов.
Модерация и compliance
Token metadata verification. IPFS хранение метаданных (имя, символ, изображение). Платформа не должна хостить illegal content — нужна система репортинга и возможность скрыть токен из UI (не on-chain, только frontend).
Spam prevention. Creation fee (небольшой SOL) снижает spam launch. Pump.fun берёт ~0.02 SOL за создание.
Процесс разработки
Смарт-контракты (4-6 недель). Bonding curve контракт → graduation механизм → fee collection → Anchor/Foundry тесты с граничными случаями (покупка последнего токена, graduation edge cases, reentrancy).
Индексер (2-3 недели). Off-chain сервис, парсящий on-chain события и строящий базу данных токенов, цен, транзакций. PostgreSQL + Redis для кэша. Это нужно для быстрого API — on-chain query слишком медленный.
API и frontend (3-4 недели). REST API для списков токенов, WebSocket для real-time updates, React frontend с TradingView charts.
Launch и мониторинг. Alert на аномальную активность (один адрес купил 10%+ supply), мониторинг gas/compute на Solana, circuit breaker если graduation механизм давит на Raydium API.
Полная платформа — 3-4 месяца. MVP без graduation и с упрощённым UI — 6-8 недель.







