Представьте: вы запускаете токенсейл, но из-за ошибки в смарт-контракте часть транзакций откатывается, или пользователи не могут получить токены после сбора. Такие инциденты стоят репутации и денег — мы видели проекты, терявшие существенные суммы из-за банального N+1 в UI. За 5+ лет мы выработали подход, исключающий эти риски: используем Merkle tree для whitelist, автоматизируем вестинг и проводим аудит контрактов. Мы разрабатываем кастомные платформы для запуска токенов — IDO/ICO Launchpad, интегрированные со смарт-контрактами пресейла. Наши решения работают на Ethereum, BNB Chain и Polygon, проходят аудит и позволяют гибко настраивать whitelist, многофазные продажи и вестинг. Frontend на React+TypeScript с использованием viem и wagmi гарантирует точность расчётов и безопасность транзакций.
Какие проблемы решаем?
Сложность управления фазами продажи. Launchpad проходит через четыре состояния: Upcoming, Whitelist Round, Public Round, Ended. Каждая фаза требует своего UI и логики. Мы автоматизируем переключение состояний на основе данных контракта, исключая ошибки ручного управления.
Whitelist с Merkle tree. Чтобы допустить к продаже только проверенных участников, мы используем Merkle tree. Это позволяет хранить список допуска offchain, а на контракте проверять только корень. Фронтенд генерирует proof для каждого адреса. Без этой механики whitelist либо дорогой (хранение массива в контракте), либо централизованный (backend-проверка). Наш подход балансирует между децентрализацией и газ-эффективностью.
Точный расчёт токенов и вестинг. Пользователи вносят ETH, получают токены по цене пресейла. Мы реализуем калькулятор с обратной связью в реальном времени, учитывая персональные лимиты и уже внесённые суммы. Вестинг настраивается: линейный или с клиффом, распределение по раундам.
Почему Merkle tree — лучший выбор для whitelist?
Хранение полного списка whitelist в смарт-контракте стоит дорого: каждая запись добавляет ~20 000 gas. При списке в 10 000 адресов это около 200 000 000 gas — экономия до $5000 при текущих ценах. Merkle tree сокращает эту стоимость в 10 раз, так как на блокчейне хранится только один 32-байтовый корень. Участник предоставляет proof, проверяемый за ~3000 gas. Это делает launchpad масштабируемым и доступным для проектов с тысячами инвесторов. Подробнее о Merkle tree.
Как мы обеспечиваем безопасность смарт-контрактов?
Все контракты пишутся на Solidity с использованием OpenZeppelin библиотек — стандарт безопасности в индустрии. Мы используем паттерны ReentrancyGuard, Pausable, Ownable. Перед релизом каждый контракт проходит внутренний аудит с Foundry (тесты покрытия >95%) и внешний аудит в сертифицированных компаниях (CertiK, Quantstamp). Дополнительно настраиваем multisig для управления средствами и мониторинг на Sentry.
Как мы строим launchpad?
- Frontend: React 18, TypeScript, Tailwind CSS, Wagmi, viem. Используем RSC и Suspense для оптимизации загрузки.
- Smart contracts: Solidity, OpenZeppelin, Foundry. Контракты пресейла с возможностью whitelist, вестинга и refund.
- Инфраструктура: Vercel для фронтенда, AWS для API и базы, IPFS для хостинга метаданных.
- Интеграции: WalletConnect, MetaMask, Coinbase Wallet, любые EVM-кошельки.
Пример: для одного из клиентов мы развернули launchpad с двухфазной продажей (whitelist + public), вестингом 6 месяцев и автоматическим клеймингом. Проект собрал hard cap за 4 часа. Все контракты проверены CertiK.
Что входит в работу
| Этап | Что делаем | Срок |
|---|---|---|
| Анализ и спецификация | Описываем бизнес-логику, фазы, лимиты, механику вестинга | 1–2 дня |
| Дизайн UI/UX | Макеты экранов для каждой фазы, десктоп + мобильные | 2–3 дня |
| Разработка смарт-контрактов | Solidity + тесты на Foundry, деплой в testnet | 3–5 дней |
| Frontend | Интеграция с контрактом, калькулятор, таймер, прогресс-бар | 4–7 дней |
| Аудит и тестирование | Внутренний аудит, code review, исправление багов | 2–4 дня |
| Запуск и сопровождение | Деплой, мониторинг, пост-релизная поддержка 2 недели | 1–2 дня |
Сравнение базового и расширенного пакета
| Параметр | MVP (базовый) | Full Launchpad |
|---|---|---|
| Количество раундов | 1 | до 5 |
| Whitelist | — | Merkle tree + tiered |
| Вестинг | — | Линейный/клифф |
| Клейминг | Вручную | Автоматически |
| Аудит | Формальный | CertiK/Quantstamp |
| Срок | 4–5 дней | 10–14 дней |
Процесс работы
- Аналитика — описываем логику, фазы, лимиты, вестинг.
- Проектирование — архитектура контрактов, UI/UX макеты.
- Реализация — контракты (Solidity) + фронтенд (React) параллельно.
- Тестирование — юнит-тесты, интеграционные тесты, code review.
- Деплой — в mainnet, мониторинг, передача документации.
Этапы могут пересекаться; сроки уточняются после брифа.
Ключевые компоненты интерфейса
Транзакция взноса с Merkle proof (нажмите, чтобы развернуть)
// hooks/useContribute.ts import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi'; import { getMerkleProof, isWhitelisted } from '@/lib/merkle'; export function useContribute(contractAddress: `0x${string}`, phase: number) { const { address } = useAccount(); const { writeContract, data: txHash, isPending } = useWriteContract(); const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({ hash: txHash }); const contribute = async (ethValue: bigint) => { if (!address) return; if (phase === 1) { if (!isWhitelisted(address)) { throw new Error('Адрес не в whitelist'); } const proof = getMerkleProof(address); writeContract({ address: contractAddress, abi: PRESALE_ABI, functionName: 'contribute', args: [proof], value: ethValue, }); } else { writeContract({ address: contractAddress, abi: PRESALE_ABI, functionName: 'contributePublic', value: ethValue, }); } }; return { contribute, txHash, isPending, isConfirming, isSuccess }; } Компонент таймера обратного отсчёта (нажмите, чтобы развернуть)
// components/CountdownTimer.tsx import { useEffect, useState } from 'react'; interface TimeLeft { days: number; hours: number; minutes: number; seconds: number; } function calcTimeLeft(targetTs: number): TimeLeft { const diff = Math.max(0, targetTs * 1000 - Date.now()); return { days: Math.floor(diff / 86_400_000), hours: Math.floor((diff % 86_400_000) / 3_600_000), minutes: Math.floor((diff % 3_600_000) / 60_000), seconds: Math.floor((diff % 60_000) / 1_000), }; } export function CountdownTimer({ targetTs, label }: { targetTs: number; label: string }) { const [timeLeft, setTimeLeft] = useState<TimeLeft>(calcTimeLeft(targetTs)); useEffect(() => { const interval = setInterval(() => setTimeLeft(calcTimeLeft(targetTs)), 1000); return () => clearInterval(interval); }, [targetTs]); return ( <div className="text-center"> <p className="mb-3 text-sm text-neutral-400">{label}</p> <div className="flex items-center gap-3"> {[ { value: timeLeft.days, label: 'дней' }, { value: timeLeft.hours, label: 'часов' }, { value: timeLeft.minutes, label: 'минут' }, { value: timeLeft.seconds, label: 'секунд' }, ].map(({ value, label }) => ( <div key={label} className="min-w-[60px] rounded-xl bg-neutral-800 p-3 text-center"> <span className="block text-2xl font-bold tabular-nums"> {String(value).padStart(2, '0')} </span> <span className="text-xs text-neutral-500">{label}</span> </div> ))} </div> </div> ); } Калькулятор распределения токенов (нажмите, чтобы развернуть)
// components/ContributionCalculator.tsx import { formatEther, formatUnits, parseEther } from 'viem'; interface Props { tokenPrice: bigint; minContrib: bigint; maxContrib: bigint; userContrib: bigint; tokenDecimals?: number; } export function ContributionCalculator({ tokenPrice, minContrib, maxContrib, userContrib, tokenDecimals = 18, }: Props) { const [ethAmount, setEthAmount] = useState(''); const ethWei = ethAmount ? parseEther(ethAmount) : 0n; const tokensReceived = tokenPrice > 0n ? (ethWei * BigInt(10 ** tokenDecimals)) / tokenPrice : 0n; const remaining = maxContrib - userContrib; const canContribute = ethWei >= minContrib && ethWei <= remaining; return ( <div className="space-y-4"> {/* original */} </div> ); } Прогресс-бар с отображением сбора (нажмите, чтобы развернуть)
function FundingProgress({ raised, hardCap, softCap }: { raised: bigint; hardCap: bigint; softCap: bigint }) { const raisedEth = parseFloat(formatEther(raised)); const hardCapEth = parseFloat(formatEther(hardCap)); const softCapEth = parseFloat(formatEther(softCap)); const progress = (raisedEth / hardCapEth) * 100; const softCapPercent = (softCapEth / hardCapEth) * 100; return ( <div> <div className="mb-2 flex justify-between text-sm"> <span>{raisedEth.toFixed(2)} ETH собрано</span> <span>{progress.toFixed(1)}%</span> </div> <div className="relative h-3 overflow-hidden rounded-full bg-neutral-800"> <div className="h-full rounded-full bg-gradient-to-r from-blue-600 to-violet-600 transition-all duration-500" style={{ width: `${Math.min(progress, 100)}%` }} /> <div className="absolute top-0 h-full w-0.5 bg-yellow-400" style={{ left: `${softCapPercent}%` }} /> </div> <div className="mt-1 flex justify-between text-xs text-neutral-500"> <span>Soft cap: {softCapEth} ETH</span> <span>Hard cap: {hardCapEth} ETH</span> </div> </div> ); } Как заказать разработку
Свяжитесь с нами через форму на сайте — мы оценим ваш проект, предложим архитектуру и сроки. Получите консультацию бесплатно. Закажите разработку launchpad под ваш проект и запустите токенсейл без рисков.







