Розробка платформи для токенсейлів (Launchpad)
Launchpad — це не просто «контракт який приймає ETH і відає токени». Це інфраструктура з IDO механікою, whitelist системою, vesting, клеймом, захистом від ботів і іноді — децентралізованим governance для вибору проектів. Основна складність не в самих смарт-контрактах, а в балансі: зробити систему достатньо відкритою для учасників, але стійкою до MEV, снайперингу та sybil-атак.
Ключові механіки та їх реалізація
Sale структури
Три основних моделі sale, кожна зі своєю механікою:
Fixed price sale — найпростіша. Ціна фіксована, перші X учасників отримують аллокації. Проблема: боти снімають аллокації в першому блоці.
Overflow / Oversubscription model — учасники вносять будь-яку суму, фінальна ціна визначається об'ємом. Якщо збрано в 3 рази більше цілі — кожен отримує 1/3 назад, 2/3 конвертується в токени. Використовують Polkastarter, CoinList.
Dutch auction — ціна стартує високою і знижується до моменту, коли весь об'єм раскупується. Знаходить "справедливу ціну" ринку, стійкий до снайперингу.
// Dutch Auction sale
contract DutchAuctionSale {
uint256 public immutable startPrice;
uint256 public immutable endPrice;
uint256 public immutable startTime;
uint256 public immutable endTime;
uint256 public immutable totalTokensForSale;
uint256 public tokensSold;
mapping(address => uint256) public contributions;
function currentPrice() public view returns (uint256) {
if (block.timestamp <= startTime) return startPrice;
if (block.timestamp >= endTime) return endPrice;
uint256 elapsed = block.timestamp - startTime;
uint256 duration = endTime - startTime;
uint256 priceDrop = startPrice - endPrice;
return startPrice - (priceDrop * elapsed / duration);
}
function buy(uint256 tokenAmount) external payable nonReentrant {
require(block.timestamp >= startTime && block.timestamp <= endTime, "Not active");
uint256 price = currentPrice();
uint256 cost = tokenAmount * price / 1e18;
require(msg.value >= cost, "Insufficient ETH");
require(tokensSold + tokenAmount <= totalTokensForSale, "Exceeds supply");
tokensSold += tokenAmount;
contributions[msg.sender] += tokenAmount;
// Повернення надлишку
if (msg.value > cost) {
payable(msg.sender).transfer(msg.value - cost);
}
}
}
Whitelist та аллокація
Merkle tree whitelist — gas-efficient стандарт whitelist. Список адресів зберігається off-chain, on-chain зберігається тільки root. Учасник надає proof при покупці:
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
bytes32 public merkleRoot;
function buyWithWhitelist(
uint256 tokenAmount,
uint256 maxAllocation, // аллокація з листа
bytes32[] calldata merkleProof
) external payable {
// Верифіцуємо що адрес в whitelist з вказаною аллокацією
bytes32 leaf = keccak256(abi.encodePacked(msg.sender, maxAllocation));
require(
MerkleProof.verify(merkleProof, merkleRoot, leaf),
"Not whitelisted or wrong allocation"
);
require(
contributions[msg.sender] + tokenAmount <= maxAllocation,
"Exceeds allocation"
);
// ... логіка покупки
}
Merkle root оновлюється при зміні whitelist — це дешевше ніж зберігати всі адреси on-chain.
Tiered allocation — розповсюджена модель у ведучих launchpads (DAO Maker, GameFi, RedKite): розмір аллокації залежить від кількості застейканих платформенних токенів. Учасники діляться на тиры (Bronze/Silver/Gold/Diamond), кожен тір має гарантовану аллокацію пропорційно кількості токенів у стейкингу.
Vesting та claim
Після IDO токени не видаються одразу — це стандарт ринку. Типовий vesting для launchpad: 20% TGE (Token Generation Event), решта лінійно за 6–12 місяців.
contract TokenVesting {
struct VestingSchedule {
uint256 totalAmount;
uint256 claimedAmount;
uint256 tgePercent; // % доступний одразу після TGE, 10000 = 100%
uint256 cliffDuration; // затримка перед лінійним вестингом
uint256 vestingDuration; // довжина лінійного vesting
uint256 tgeTimestamp;
}
mapping(address => VestingSchedule) public schedules;
function claimableAmount(address beneficiary) public view returns (uint256) {
VestingSchedule storage schedule = schedules[beneficiary];
if (schedule.totalAmount == 0) return 0;
uint256 tgeAmount = schedule.totalAmount * schedule.tgePercent / 10000;
if (block.timestamp < schedule.tgeTimestamp) {
return 0;
}
uint256 cliffEnd = schedule.tgeTimestamp + schedule.cliffDuration;
if (block.timestamp < cliffEnd) {
return tgeAmount > schedule.claimedAmount
? tgeAmount - schedule.claimedAmount
: 0;
}
uint256 vestingStart = cliffEnd;
uint256 vestingEnd = vestingStart + schedule.vestingDuration;
uint256 elapsed = min(block.timestamp, vestingEnd) - vestingStart;
uint256 vestedLinear = (schedule.totalAmount - tgeAmount)
* elapsed / schedule.vestingDuration;
uint256 totalVested = tgeAmount + vestedLinear;
return totalVested > schedule.claimedAmount
? totalVested - schedule.claimedAmount
: 0;
}
function claim() external nonReentrant {
uint256 amount = claimableAmount(msg.sender);
require(amount > 0, "Nothing to claim");
schedules[msg.sender].claimedAmount += amount;
saleToken.safeTransfer(msg.sender, amount);
emit TokensClaimed(msg.sender, amount);
}
}
Захист від MEV та ботів
Anti-sniper механіки
Боти мониторять mempool і пытаются купити в першому блоці продажи. Стандартні захисти:
Commit-reveal scheme — учасник спочатку відправляє commit = keccak256(amount, salt, address) без розкриття суми. У наступної фазі розкриває amount і salt. Боти не знають точну суму до reveal.
Randomized start — точне време старту має випадкову затримку (напр., випадковий offset 0–300 секунд). Chainlink VRF для джерела випадковості.
Per-block limit — не більше X покупок за блок, або максимальна сума за блок:
uint256 public maxContributionPerBlock;
mapping(uint256 => uint256) public blockContributions;
function buy(uint256 amount) external payable {
require(
blockContributions[block.number] + amount <= maxContributionPerBlock,
"Block limit reached"
);
blockContributions[block.number] += amount;
// ...
}
KYC інтеграція
Для регульованих ринків — інтеграція з KYC провайдерами. Frontend KYC (Sumsub, Onfido, Synaps) видає підписаний JWT. Backend верифіцує JWT і додає адресу в whitelist через транзакцію.
Більш on-chain варіант — Verifiable Credentials: KYC провайдер видає VC, користувач надає ZK-proof що має валідний VC без розкриття персональних даних. Реалізації: Polygon ID, Worldcoin (з застереженнями про приватність).
Адміністративна панель та листинг
Launchpad — це не тільки смарт-контракти. Повноцінний продукт включає:
Для проектів (листинг):
- Форма подачи заявки з верифікацією контракту
- Admin workflow для одобрення/відхилення
- Настройка параметрів sale: ціна, hard cap, soft cap, дати, whitelist, vesting
- Загрузка whitelist CSV → merkle tree генерація
Для учасників:
- Dashboard з активними та минулими сейлами
- KYC онбординг
- Whitelist реєстрація з підключеним кошельком
- Claim інтерфейс з графіком vesting
Для адміністраторів:
- Мониторинг прогресу сейла в реальному часі
- Emergency pause
- Управління whitelist (додавання/видалення)
- Вивід зібраних коштів після фіналізації
Економіка платформи
Launchpad зазвичай монетизується через:
- Процент від raise — 3–8% від зібраних коштів
- Токен аллокація — X% токенів продаваємого проекту
- Платформенний токен — стейкинг для отримання аллокацій (lock-in екосистеми)
Етапи розробки
| Фаза | Вміст | Термін |
|---|---|---|
| Design | Sale механіки, vesting схеми, tier структура, tokenomics | 2–3 тижні |
| Core contracts | Sale, Vesting, Staking, Whitelist | 4–5 тижнів |
| Testing | Unit, integration, fork тести, fuzz | 2–3 тижні |
| Backend | API, merkle tree generation, KYC інтеграція | 3–4 тижні |
| Frontend | Participant dashboard, admin panel | 4–5 тижнів |
| Audit | Контракти + backend | 3–4 тижні |
| Testnet pilot | Один тестовий IDO | 2–3 тижні |
Всього: 20–27 тижнів. Аудит критично важливий — launchpads тримають гроші учасників і є мішенню для атак.







